Decompiled source of City Services Rebalance v0.2.0

0Harmony.dll

Decompiled 9 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
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.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using HarmonyLib.Internal.Patching;
using HarmonyLib.Internal.RuntimeFixes;
using HarmonyLib.Internal.Util;
using HarmonyLib.Public.Patching;
using HarmonyLib.Tools;
using JetBrains.Annotations;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using MonoMod.Utils.Cil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: ComVisible(false)]
[assembly: InternalsVisibleTo("HarmonyTests")]
[assembly: InternalsVisibleTo("MonoMod.Utils.Cil.ILGeneratorProxy")]
[assembly: Guid("69aee16a-b6e7-4642-8081-3928b32455df")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("BepInEx")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © BepInEx 2022")]
[assembly: AssemblyDescription("A library for patching, replacing and decorating .NET and Mono methods during runtime powered by MonoMod.")]
[assembly: AssemblyFileVersion("2.10.2.0")]
[assembly: AssemblyInformationalVersion("2.10.2")]
[assembly: AssemblyProduct("HarmonyX")]
[assembly: AssemblyTitle("0Harmony")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.10.2.0")]
[module: UnverifiableCode]
namespace JetBrains.Annotations
{
	[AttributeUsage(AttributeTargets.All)]
	internal sealed class UsedImplicitlyAttribute : Attribute
	{
		public ImplicitUseKindFlags UseKindFlags { get; }

		public ImplicitUseTargetFlags TargetFlags { get; }

		public UsedImplicitlyAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public UsedImplicitlyAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Parameter | AttributeTargets.GenericParameter)]
	internal sealed class MeansImplicitUseAttribute : Attribute
	{
		[UsedImplicitly]
		public ImplicitUseKindFlags UseKindFlags { get; }

		[UsedImplicitly]
		public ImplicitUseTargetFlags TargetFlags { get; }

		public MeansImplicitUseAttribute()
			: this(ImplicitUseKindFlags.Default, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags)
			: this(useKindFlags, ImplicitUseTargetFlags.Default)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseTargetFlags targetFlags)
			: this(ImplicitUseKindFlags.Default, targetFlags)
		{
		}

		public MeansImplicitUseAttribute(ImplicitUseKindFlags useKindFlags, ImplicitUseTargetFlags targetFlags)
		{
			UseKindFlags = useKindFlags;
			TargetFlags = targetFlags;
		}
	}
	[Flags]
	internal enum ImplicitUseKindFlags
	{
		Default = 7,
		Access = 1,
		Assign = 2,
		InstantiatedWithFixedConstructorSignature = 4,
		InstantiatedNoFixedConstructorSignature = 8
	}
	[Flags]
	internal enum ImplicitUseTargetFlags
	{
		Default = 1,
		Itself = 1,
		Members = 2,
		WithInheritors = 4,
		WithMembers = 3
	}
}
namespace HarmonyLib
{
	public class DelegateTypeFactory
	{
		private class DelegateEntry
		{
			public CallingConvention? callingConvention;

			public Type delegateType;
		}

		private static int counter;

		private static readonly Dictionary<MethodInfo, List<DelegateEntry>> TypeCache = new Dictionary<MethodInfo, List<DelegateEntry>>();

		private static readonly MethodBase CallingConvAttr = AccessTools.Constructor(typeof(UnmanagedFunctionPointerAttribute), new Type[1] { typeof(CallingConvention) });

		public static readonly DelegateTypeFactory instance = new DelegateTypeFactory();

		public Type CreateDelegateType(Type returnType, Type[] argTypes)
		{
			return CreateDelegateType(returnType, argTypes, null);
		}

		public Type CreateDelegateType(Type returnType, Type[] argTypes, CallingConvention? convention)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			counter++;
			AssemblyDefinition val = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition($"HarmonyDTFAssembly{counter}", new Version(1, 0)), $"HarmonyDTFModule{counter}", (ModuleKind)0);
			ModuleDefinition module = val.MainModule;
			TypeDefinition val2 = new TypeDefinition("", $"HarmonyDTFType{counter}", (TypeAttributes)257)
			{
				BaseType = module.ImportReference(typeof(MulticastDelegate))
			};
			module.Types.Add(val2);
			if (convention.HasValue)
			{
				CustomAttribute val3 = new CustomAttribute(module.ImportReference(CallingConvAttr));
				val3.ConstructorArguments.Add(new CustomAttributeArgument(module.ImportReference(typeof(CallingConvention)), (object)convention.Value));
				val2.CustomAttributes.Add(val3);
			}
			MethodDefinition val4 = new MethodDefinition(".ctor", (MethodAttributes)4230, module.ImportReference(typeof(void)))
			{
				ImplAttributes = (MethodImplAttributes)3
			};
			Extensions.AddRange<ParameterDefinition>(((MethodReference)val4).Parameters, (IEnumerable<ParameterDefinition>)(object)new ParameterDefinition[2]
			{
				new ParameterDefinition(module.ImportReference(typeof(object))),
				new ParameterDefinition(module.ImportReference(typeof(IntPtr)))
			});
			val2.Methods.Add(val4);
			MethodDefinition val5 = new MethodDefinition("Invoke", (MethodAttributes)198, module.ImportReference(returnType))
			{
				ImplAttributes = (MethodImplAttributes)3
			};
			Extensions.AddRange<ParameterDefinition>(((MethodReference)val5).Parameters, ((IEnumerable<Type>)argTypes).Select((Func<Type, ParameterDefinition>)((Type t) => new ParameterDefinition(module.ImportReference(t)))));
			val2.Methods.Add(val5);
			return ReflectionHelper.Load(val.MainModule).GetType($"HarmonyDTFType{counter}");
		}

		public Type CreateDelegateType(MethodInfo method)
		{
			return CreateDelegateType(method, null);
		}

		public Type CreateDelegateType(MethodInfo method, CallingConvention? convention)
		{
			DelegateEntry delegateEntry;
			if (TypeCache.TryGetValue(method, out var value) && (delegateEntry = value.FirstOrDefault((DelegateEntry e) => e.callingConvention == convention)) != null)
			{
				return delegateEntry.delegateType;
			}
			if (value == null)
			{
				value = (TypeCache[method] = new List<DelegateEntry>());
			}
			delegateEntry = new DelegateEntry
			{
				delegateType = CreateDelegateType(method.ReturnType, method.GetParameters().Types().ToArray(), convention),
				callingConvention = convention
			};
			value.Add(delegateEntry);
			return delegateEntry.delegateType;
		}
	}
	[Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Func<T, S>> for property getters")]
	public delegate S GetterHandler<in T, out S>(T source);
	[Obsolete("Use AccessTools.FieldRefAccess<T, S> for fields and AccessTools.MethodDelegate<Action<T, S>> for property setters")]
	public delegate void SetterHandler<in T, in S>(T source, S value);
	public delegate T InstantiationHandler<out T>();
	public static class FastAccess
	{
		public static InstantiationHandler<T> CreateInstantiationHandler<T>()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null);
			if ((object)constructor == null)
			{
				throw new ApplicationException($"The type {typeof(T)} must declare an empty constructor (the constructor may be private, internal, protected, protected internal, or public).");
			}
			DynamicMethodDefinition val = new DynamicMethodDefinition("InstantiateObject_" + typeof(T).Name, typeof(T), (Type[])null);
			ILGenerator iLGenerator = val.GetILGenerator();
			iLGenerator.Emit(OpCodes.Newobj, constructor);
			iLGenerator.Emit(OpCodes.Ret);
			return (InstantiationHandler<T>)val.Generate().CreateDelegate(typeof(InstantiationHandler<T>));
		}

		[Obsolete("Use AccessTools.MethodDelegate<Func<T, S>>(PropertyInfo.GetGetMethod(true))")]
		public static GetterHandler<T, S> CreateGetterHandler<T, S>(PropertyInfo propertyInfo)
		{
			MethodInfo getMethod = propertyInfo.GetGetMethod(nonPublic: true);
			DynamicMethodDefinition obj = CreateGetDynamicMethod<T, S>(propertyInfo.DeclaringType);
			ILGenerator iLGenerator = obj.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Call, getMethod);
			iLGenerator.Emit(OpCodes.Ret);
			return (GetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(GetterHandler<T, S>));
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")]
		public static GetterHandler<T, S> CreateGetterHandler<T, S>(FieldInfo fieldInfo)
		{
			DynamicMethodDefinition obj = CreateGetDynamicMethod<T, S>(fieldInfo.DeclaringType);
			ILGenerator iLGenerator = obj.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldfld, fieldInfo);
			iLGenerator.Emit(OpCodes.Ret);
			return (GetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(GetterHandler<T, S>));
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(name) for fields and AccessTools.MethodDelegate<Func<T, S>>(AccessTools.PropertyGetter(typeof(T), name)) for properties")]
		public static GetterHandler<T, S> CreateFieldGetter<T, S>(params string[] names)
		{
			foreach (string name in names)
			{
				FieldInfo field = typeof(T).GetField(name, AccessTools.all);
				if ((object)field != null)
				{
					return CreateGetterHandler<T, S>(field);
				}
				PropertyInfo property = typeof(T).GetProperty(name, AccessTools.all);
				if ((object)property != null)
				{
					return CreateGetterHandler<T, S>(property);
				}
			}
			return null;
		}

		[Obsolete("Use AccessTools.MethodDelegate<Action<T, S>>(PropertyInfo.GetSetMethod(true))")]
		public static SetterHandler<T, S> CreateSetterHandler<T, S>(PropertyInfo propertyInfo)
		{
			MethodInfo setMethod = propertyInfo.GetSetMethod(nonPublic: true);
			DynamicMethodDefinition obj = CreateSetDynamicMethod<T, S>(propertyInfo.DeclaringType);
			ILGenerator iLGenerator = obj.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldarg_1);
			iLGenerator.Emit(OpCodes.Call, setMethod);
			iLGenerator.Emit(OpCodes.Ret);
			return (SetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(SetterHandler<T, S>));
		}

		[Obsolete("Use AccessTools.FieldRefAccess<T, S>(fieldInfo)")]
		public static SetterHandler<T, S> CreateSetterHandler<T, S>(FieldInfo fieldInfo)
		{
			DynamicMethodDefinition obj = CreateSetDynamicMethod<T, S>(fieldInfo.DeclaringType);
			ILGenerator iLGenerator = obj.GetILGenerator();
			iLGenerator.Emit(OpCodes.Ldarg_0);
			iLGenerator.Emit(OpCodes.Ldarg_1);
			iLGenerator.Emit(OpCodes.Stfld, fieldInfo);
			iLGenerator.Emit(OpCodes.Ret);
			return (SetterHandler<T, S>)obj.Generate().CreateDelegate(typeof(SetterHandler<T, S>));
		}

		private static DynamicMethodDefinition CreateGetDynamicMethod<T, S>(Type type)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			return new DynamicMethodDefinition("DynamicGet_" + type.Name, typeof(S), new Type[1] { typeof(T) });
		}

		private static DynamicMethodDefinition CreateSetDynamicMethod<T, S>(Type type)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			return new DynamicMethodDefinition("DynamicSet_" + type.Name, typeof(void), new Type[2]
			{
				typeof(T),
				typeof(S)
			});
		}
	}
	public delegate object FastInvokeHandler(object target, params object[] parameters);
	public static class MethodInvoker
	{
		public static FastInvokeHandler GetHandler(MethodInfo methodInfo, bool directBoxValueAccess = false)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			DynamicMethodDefinition val = new DynamicMethodDefinition("FastInvoke_" + methodInfo.Name + "_" + (directBoxValueAccess ? "direct" : "indirect"), typeof(object), new Type[2]
			{
				typeof(object),
				typeof(object[])
			});
			ILGenerator iLGenerator = val.GetILGenerator();
			if (!methodInfo.IsStatic)
			{
				Emit(iLGenerator, OpCodes.Ldarg_0);
				EmitUnboxIfNeeded(iLGenerator, methodInfo.DeclaringType);
			}
			bool flag = true;
			ParameterInfo[] parameters = methodInfo.GetParameters();
			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)
				{
					Emit(iLGenerator, OpCodes.Ldarg_1);
					EmitFastInt(iLGenerator, i);
				}
				Emit(iLGenerator, OpCodes.Ldarg_1);
				EmitFastInt(iLGenerator, i);
				if (isByRef && !isValueType)
				{
					Emit(iLGenerator, OpCodes.Ldelema, typeof(object));
					continue;
				}
				Emit(iLGenerator, OpCodes.Ldelem_Ref);
				if (!isValueType)
				{
					continue;
				}
				if (!isByRef || !directBoxValueAccess)
				{
					Emit(iLGenerator, OpCodes.Unbox_Any, type);
					if (isByRef)
					{
						Emit(iLGenerator, OpCodes.Box, type);
						Emit(iLGenerator, OpCodes.Dup);
						if (flag)
						{
							flag = false;
							iLGenerator.DeclareLocal(typeof(object), pinned: false);
						}
						Emit(iLGenerator, OpCodes.Stloc_0);
						Emit(iLGenerator, OpCodes.Stelem_Ref);
						Emit(iLGenerator, OpCodes.Ldloc_0);
						Emit(iLGenerator, OpCodes.Unbox, type);
					}
				}
				else
				{
					Emit(iLGenerator, OpCodes.Unbox, type);
				}
			}
			if (methodInfo.IsStatic)
			{
				EmitCall(iLGenerator, OpCodes.Call, methodInfo);
			}
			else
			{
				EmitCall(iLGenerator, OpCodes.Callvirt, methodInfo);
			}
			if (methodInfo.ReturnType == typeof(void))
			{
				Emit(iLGenerator, OpCodes.Ldnull);
			}
			else
			{
				EmitBoxIfNeeded(iLGenerator, methodInfo.ReturnType);
			}
			Emit(iLGenerator, OpCodes.Ret);
			return (FastInvokeHandler)val.Generate().CreateDelegate(typeof(FastInvokeHandler));
		}

		internal static void Emit(ILGenerator il, OpCode opcode)
		{
			il.Emit(opcode);
		}

		internal static void Emit(ILGenerator il, OpCode opcode, Type type)
		{
			il.Emit(opcode, type);
		}

		internal static void EmitCall(ILGenerator il, OpCode opcode, MethodInfo methodInfo)
		{
			il.EmitCall(opcode, methodInfo, null);
		}

		private static void EmitUnboxIfNeeded(ILGenerator il, Type type)
		{
			if (type.IsValueType)
			{
				Emit(il, OpCodes.Unbox_Any, type);
			}
		}

		private static void EmitBoxIfNeeded(ILGenerator il, Type type)
		{
			if (type.IsValueType)
			{
				Emit(il, OpCodes.Box, type);
			}
		}

		internal static void EmitFastInt(ILGenerator il, int value)
		{
			switch (value)
			{
			case -1:
				il.Emit(OpCodes.Ldc_I4_M1);
				return;
			case 0:
				il.Emit(OpCodes.Ldc_I4_0);
				return;
			case 1:
				il.Emit(OpCodes.Ldc_I4_1);
				return;
			case 2:
				il.Emit(OpCodes.Ldc_I4_2);
				return;
			case 3:
				il.Emit(OpCodes.Ldc_I4_3);
				return;
			case 4:
				il.Emit(OpCodes.Ldc_I4_4);
				return;
			case 5:
				il.Emit(OpCodes.Ldc_I4_5);
				return;
			case 6:
				il.Emit(OpCodes.Ldc_I4_6);
				return;
			case 7:
				il.Emit(OpCodes.Ldc_I4_7);
				return;
			case 8:
				il.Emit(OpCodes.Ldc_I4_8);
				return;
			}
			if (value > -129 && value < 128)
			{
				il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
			}
			else
			{
				il.Emit(OpCodes.Ldc_I4, value);
			}
		}
	}
	internal class AccessCache
	{
		internal enum MemberType
		{
			Any,
			Static,
			Instance
		}

		private const BindingFlags BasicFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty;

		private static readonly Dictionary<MemberType, BindingFlags> declaredOnlyBindingFlags = new Dictionary<MemberType, BindingFlags>
		{
			{
				MemberType.Any,
				BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			},
			{
				MemberType.Instance,
				BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			},
			{
				MemberType.Static,
				BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.GetProperty | BindingFlags.SetProperty
			}
		};

		private readonly Dictionary<Type, Dictionary<string, FieldInfo>> declaredFields = new Dictionary<Type, Dictionary<string, FieldInfo>>();

		private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> declaredProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

		private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> declaredMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>();

		private readonly Dictionary<Type, Dictionary<string, FieldInfo>> inheritedFields = new Dictionary<Type, Dictionary<string, FieldInfo>>();

		private readonly Dictionary<Type, Dictionary<string, PropertyInfo>> inheritedProperties = new Dictionary<Type, Dictionary<string, PropertyInfo>>();

		private readonly Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>> inheritedMethods = new Dictionary<Type, Dictionary<string, Dictionary<int, MethodBase>>>();

		private static T Get<T>(Dictionary<Type, Dictionary<string, T>> dict, Type type, string name, Func<T> fetcher)
		{
			lock (dict)
			{
				if (!dict.TryGetValue(type, out var value))
				{
					value = (dict[type] = new Dictionary<string, T>());
				}
				if (!value.TryGetValue(name, out var value2))
				{
					value2 = (value[name] = fetcher());
				}
				return value2;
			}
		}

		private static T Get<T>(Dictionary<Type, Dictionary<string, Dictionary<int, T>>> dict, Type type, string name, Type[] arguments, Func<T> fetcher)
		{
			lock (dict)
			{
				if (!dict.TryGetValue(type, out var value))
				{
					value = (dict[type] = new Dictionary<string, Dictionary<int, T>>());
				}
				if (!value.TryGetValue(name, out var value2))
				{
					value2 = (value[name] = new Dictionary<int, T>());
				}
				int key = AccessTools.CombinedHashCode(arguments);
				if (!value2.TryGetValue(key, out var value3))
				{
					value3 = (value2[key] = fetcher());
				}
				return value3;
			}
		}

		internal FieldInfo GetFieldInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			FieldInfo fieldInfo = Get(declaredFields, type, name, () => type.GetField(name, declaredOnlyBindingFlags[memberType]));
			if ((object)fieldInfo == null && !declaredOnly)
			{
				fieldInfo = Get(inheritedFields, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetField(name, AccessTools.all)));
			}
			return fieldInfo;
		}

		internal PropertyInfo GetPropertyInfo(Type type, string name, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			PropertyInfo propertyInfo = Get(declaredProperties, type, name, () => type.GetProperty(name, declaredOnlyBindingFlags[memberType]));
			if ((object)propertyInfo == null && !declaredOnly)
			{
				propertyInfo = Get(inheritedProperties, type, name, () => AccessTools.FindIncludingBaseTypes(type, (Type t) => t.GetProperty(name, AccessTools.all)));
			}
			return propertyInfo;
		}

		internal MethodBase GetMethodInfo(Type type, string name, Type[] arguments, MemberType memberType = MemberType.Any, bool declaredOnly = false)
		{
			MethodBase methodBase = Get(declaredMethods, type, name, arguments, () => type.GetMethod(name, declaredOnlyBindingFlags[memberType], null, arguments, null));
			if ((object)methodBase == null && !declaredOnly)
			{
				methodBase = Get(inheritedMethods, type, name, arguments, () => AccessTools.Method(type, name, arguments));
			}
			return methodBase;
		}
	}
	internal static class PatchArgumentExtensions
	{
		private static HarmonyArgument[] AllHarmonyArguments(object[] attributes)
		{
			return (from attr in attributes
				select (attr.GetType().Name != "HarmonyArgument") ? null : AccessTools.MakeDeepCopy<HarmonyArgument>(attr) into harg
				where harg != null
				select harg).ToArray();
		}

		private static HarmonyArgument GetArgumentAttribute(this ParameterInfo parameter)
		{
			return AllHarmonyArguments(parameter.GetCustomAttributes(inherit: false)).FirstOrDefault();
		}

		private static HarmonyArgument[] GetArgumentAttributes(this MethodInfo method)
		{
			if ((object)method == null || method is DynamicMethod)
			{
				return null;
			}
			return AllHarmonyArguments(method.GetCustomAttributes(inherit: false));
		}

		private static HarmonyArgument[] GetArgumentAttributes(this Type type)
		{
			return AllHarmonyArguments(type.GetCustomAttributes(inherit: false));
		}

		private static string GetOriginalArgumentName(this ParameterInfo parameter, string[] originalParameterNames)
		{
			HarmonyArgument argumentAttribute = parameter.GetArgumentAttribute();
			if (argumentAttribute == null)
			{
				return null;
			}
			if (!string.IsNullOrEmpty(argumentAttribute.OriginalName))
			{
				return argumentAttribute.OriginalName;
			}
			if (argumentAttribute.Index >= 0 && argumentAttribute.Index < originalParameterNames.Length)
			{
				return originalParameterNames[argumentAttribute.Index];
			}
			return null;
		}

		private static string GetOriginalArgumentName(HarmonyArgument[] attributes, string name, string[] originalParameterNames)
		{
			if (((attributes != null && attributes.Length != 0) ? 1 : 0) <= (false ? 1 : 0))
			{
				return null;
			}
			HarmonyArgument harmonyArgument = attributes.SingleOrDefault((HarmonyArgument p) => p.NewName == name);
			if (harmonyArgument == null)
			{
				return null;
			}
			if (!string.IsNullOrEmpty(harmonyArgument.OriginalName))
			{
				return harmonyArgument.OriginalName;
			}
			if (originalParameterNames != null && harmonyArgument.Index >= 0 && harmonyArgument.Index < originalParameterNames.Length)
			{
				return originalParameterNames[harmonyArgument.Index];
			}
			return null;
		}

		private static string GetOriginalArgumentName(this MethodInfo method, string[] originalParameterNames, string name)
		{
			string originalArgumentName = GetOriginalArgumentName(((object)method != null) ? method.GetArgumentAttributes() : null, name, originalParameterNames);
			if (originalArgumentName != null)
			{
				return originalArgumentName;
			}
			object attributes;
			if ((object)method == null)
			{
				attributes = null;
			}
			else
			{
				Type? declaringType = method.DeclaringType;
				attributes = (((object)declaringType != null) ? declaringType.GetArgumentAttributes() : null);
			}
			originalArgumentName = GetOriginalArgumentName((HarmonyArgument[])attributes, name, originalParameterNames);
			if (originalArgumentName != null)
			{
				return originalArgumentName;
			}
			return name;
		}

		internal static int GetArgumentIndex(this MethodInfo patch, string[] originalParameterNames, ParameterInfo patchParam)
		{
			if (patch is DynamicMethod)
			{
				return Array.IndexOf<string>(originalParameterNames, patchParam.Name);
			}
			string originalArgumentName = patchParam.GetOriginalArgumentName(originalParameterNames);
			if (originalArgumentName != null)
			{
				return Array.IndexOf(originalParameterNames, originalArgumentName);
			}
			originalArgumentName = patch.GetOriginalArgumentName(originalParameterNames, patchParam.Name);
			if (originalArgumentName != null)
			{
				return Array.IndexOf(originalParameterNames, originalArgumentName);
			}
			return -1;
		}
	}
	internal static class PatchFunctions
	{
		internal static List<MethodInfo> GetSortedPatchMethods(MethodBase original, Patch[] patches, bool debug)
		{
			return new PatchSorter(patches, debug).Sort(original);
		}

		internal static Patch[] GetSortedPatchMethodsAsPatches(MethodBase original, Patch[] patches, bool debug)
		{
			return new PatchSorter(patches, debug).SortAsPatches(original);
		}

		internal static MethodInfo UpdateWrapper(MethodBase original, PatchInfo patchInfo)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			MethodPatcher methodPatcher = original.GetMethodPatcher();
			DynamicMethodDefinition val = methodPatcher.PrepareOriginal();
			if (val != null)
			{
				ILContext ctx = new ILContext(val.Definition);
				HarmonyManipulator.Manipulate(original, patchInfo, ctx);
			}
			try
			{
				return methodPatcher.DetourTo((val != null) ? val.Generate() : null) as MethodInfo;
			}
			catch (Exception ex)
			{
				object body;
				if (val == null)
				{
					body = null;
				}
				else
				{
					MethodDefinition definition = val.Definition;
					body = ((definition != null) ? definition.Body : null);
				}
				throw HarmonyException.Create(ex, (MethodBody)body);
			}
		}

		internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler, MethodInfo postManipulator)
		{
			//IL_0162: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			if (standin == null)
			{
				throw new ArgumentNullException("standin");
			}
			if ((object)standin.method == null)
			{
				throw new ArgumentNullException("standin", "standin.method is NULL");
			}
			if (!standin.method.IsStatic)
			{
				throw new ArgumentException("standin", "standin.method is not static");
			}
			bool debug = standin.debug.GetValueOrDefault();
			List<MethodInfo> transpilers = new List<MethodInfo>();
			List<MethodInfo> ilmanipulators = new List<MethodInfo>();
			if (standin.reversePatchType == HarmonyReversePatchType.Snapshot)
			{
				Patches patchInfo = Harmony.GetPatchInfo(original);
				transpilers.AddRange(GetSortedPatchMethods(original, patchInfo.Transpilers.ToArray(), debug));
				ilmanipulators.AddRange(GetSortedPatchMethods(original, patchInfo.ILManipulators.ToArray(), debug));
			}
			if ((object)postTranspiler != null)
			{
				transpilers.Add(postTranspiler);
			}
			if ((object)postManipulator != null)
			{
				ilmanipulators.Add(postManipulator);
			}
			Logger.Log(Logger.LogChannel.Info, delegate
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("Reverse patching " + standin.method.FullDescription() + " with " + original.FullDescription());
				PrintInfo(stringBuilder, transpilers, "Transpiler");
				PrintInfo(stringBuilder, ilmanipulators, "Manipulators");
				return stringBuilder.ToString();
			}, debug);
			MethodBody patchBody = null;
			ILHook val = new ILHook((MethodBase)standin.method, (Manipulator)delegate(ILContext ctx)
			{
				//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: Expected O, but got Unknown
				//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
				if (original is MethodInfo methodInfo2)
				{
					patchBody = ctx.Body;
					MethodPatcher methodPatcher = methodInfo2.GetMethodPatcher();
					DynamicMethodDefinition val2 = methodPatcher.CopyOriginal();
					if (val2 == null)
					{
						throw new NullReferenceException("Cannot reverse patch " + methodInfo2.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body");
					}
					ILManipulator iLManipulator = new ILManipulator(val2.Definition.Body, debug);
					ctx.Body.Variables.Clear();
					Enumerator<VariableDefinition> enumerator2 = iLManipulator.Body.Variables.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							VariableDefinition current2 = enumerator2.Current;
							ctx.Body.Variables.Add(new VariableDefinition(ctx.Module.ImportReference(((VariableReference)current2).VariableType)));
						}
					}
					finally
					{
						((IDisposable)enumerator2).Dispose();
					}
					foreach (MethodInfo item in transpilers)
					{
						iLManipulator.AddTranspiler(item);
					}
					iLManipulator.WriteTo(ctx.Body, standin.method);
					HarmonyManipulator.ApplyManipulators(ctx, original, ilmanipulators, null);
					Instruction val3 = null;
					foreach (Instruction item2 in ((IEnumerable<Instruction>)ctx.Instrs).Where((Instruction i) => i.OpCode == OpCodes.Ret))
					{
						if (val3 == null)
						{
							val3 = ctx.IL.Create(OpCodes.Ret);
						}
						item2.OpCode = OpCodes.Br;
						item2.Operand = val3;
					}
					if (val3 != null)
					{
						ctx.IL.Append(val3);
					}
					Logger.Log(Logger.LogChannel.IL, () => "Generated reverse patcher (" + ((MemberReference)ctx.Method).FullName + "):\n" + ctx.Body.ToILDasmString(), debug);
				}
			}, new ILHookConfig
			{
				ManualApply = true
			});
			try
			{
				val.Apply();
			}
			catch (Exception ex)
			{
				throw HarmonyException.Create(ex, patchBody);
			}
			MethodInfo methodInfo = val.GetCurrentTarget() as MethodInfo;
			PatchTools.RememberObject(standin.method, methodInfo);
			return methodInfo;
			static void PrintInfo(StringBuilder sb, ICollection<MethodInfo> methods, string name)
			{
				if (methods.Count <= 0)
				{
					return;
				}
				sb.AppendLine(name + ":");
				foreach (MethodInfo method in methods)
				{
					sb.AppendLine("  * " + method.FullDescription());
				}
			}
		}

		internal static IEnumerable<CodeInstruction> ApplyTranspilers(MethodBase methodBase, ILGenerator generator, int maxTranspilers = 0)
		{
			MethodPatcher methodPatcher = methodBase.GetMethodPatcher();
			DynamicMethodDefinition val = methodPatcher.CopyOriginal();
			if (val == null)
			{
				throw new NullReferenceException("Cannot reverse patch " + methodBase.FullDescription() + ": method patcher (" + methodPatcher.GetType().FullDescription() + ") can't copy original method body");
			}
			ILManipulator iLManipulator = new ILManipulator(val.Definition.Body, debug: false);
			PatchInfo patchInfo = methodBase.GetPatchInfo();
			if (patchInfo != null)
			{
				List<MethodInfo> sortedPatchMethods = GetSortedPatchMethods(methodBase, patchInfo.transpilers, debug: false);
				for (int i = 0; i < maxTranspilers && i < sortedPatchMethods.Count; i++)
				{
					iLManipulator.AddTranspiler(sortedPatchMethods[i]);
				}
			}
			return iLManipulator.GetInstructions(generator, methodBase);
		}

		internal static void UnpatchConditional(Func<Patch, bool> executionCondition)
		{
			foreach (MethodBase item in PatchProcessor.GetAllPatchedMethods().ToList())
			{
				bool num = item.HasMethodBody();
				Patches patchInfo2 = PatchProcessor.GetPatchInfo(item);
				PatchProcessor patchProcessor = new PatchProcessor(null, item);
				if (num)
				{
					patchInfo2.Postfixes.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
					patchInfo2.Prefixes.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
				}
				patchInfo2.ILManipulators.DoIf(executionCondition, delegate(Patch patchInfo)
				{
					patchProcessor.Unpatch(patchInfo.PatchMethod);
				});
				patchInfo2.Transpilers.DoIf(executionCondition, delegate(Patch patchInfo)
				{
					patchProcessor.Unpatch(patchInfo.PatchMethod);
				});
				if (num)
				{
					patchInfo2.Finalizers.DoIf(executionCondition, delegate(Patch patchInfo)
					{
						patchProcessor.Unpatch(patchInfo.PatchMethod);
					});
				}
			}
		}
	}
	internal class PatchJobs<T>
	{
		internal class Job
		{
			internal MethodBase original;

			internal T replacement;

			internal List<HarmonyMethod> prefixes = new List<HarmonyMethod>();

			internal List<HarmonyMethod> postfixes = new List<HarmonyMethod>();

			internal List<HarmonyMethod> transpilers = new List<HarmonyMethod>();

			internal List<HarmonyMethod> finalizers = new List<HarmonyMethod>();

			internal List<HarmonyMethod> ilmanipulators = new List<HarmonyMethod>();

			internal void AddPatch(AttributePatch patch)
			{
				HarmonyPatchType? type = patch.type;
				if (type.HasValue)
				{
					switch (type.GetValueOrDefault())
					{
					case HarmonyPatchType.Prefix:
						prefixes.Add(patch.info);
						break;
					case HarmonyPatchType.Postfix:
						postfixes.Add(patch.info);
						break;
					case HarmonyPatchType.Transpiler:
						transpilers.Add(patch.info);
						break;
					case HarmonyPatchType.Finalizer:
						finalizers.Add(patch.info);
						break;
					case HarmonyPatchType.ILManipulator:
						ilmanipulators.Add(patch.info);
						break;
					case HarmonyPatchType.ReversePatch:
						break;
					}
				}
			}
		}

		internal Dictionary<MethodBase, Job> state = new Dictionary<MethodBase, Job>();

		internal Job GetJob(MethodBase method)
		{
			if ((object)method == null)
			{
				return null;
			}
			if (!state.TryGetValue(method, out var value))
			{
				value = new Job
				{
					original = method
				};
				state[method] = value;
			}
			return value;
		}

		internal List<Job> GetJobs()
		{
			return state.Values.Where((Job job) => job.prefixes.Count + job.postfixes.Count + job.transpilers.Count + job.finalizers.Count + job.ilmanipulators.Count > 0).ToList();
		}

		internal List<T> GetReplacements()
		{
			return state.Values.Select((Job job) => job.replacement).ToList();
		}
	}
	internal class AttributePatch
	{
		private static readonly HarmonyPatchType[] allPatchTypes = new HarmonyPatchType[6]
		{
			HarmonyPatchType.Prefix,
			HarmonyPatchType.Postfix,
			HarmonyPatchType.Transpiler,
			HarmonyPatchType.Finalizer,
			HarmonyPatchType.ReversePatch,
			HarmonyPatchType.ILManipulator
		};

		internal HarmonyMethod info;

		internal HarmonyPatchType? type;

		private static readonly string harmonyAttributeName = typeof(HarmonyAttribute).FullName;

		internal static IEnumerable<AttributePatch> Create(MethodInfo patch, bool collectIncomplete = false)
		{
			if ((object)patch == null)
			{
				throw new NullReferenceException("Patch method cannot be null");
			}
			object[] customAttributes = patch.GetCustomAttributes(inherit: true);
			string name = patch.Name;
			HarmonyPatchType? type = GetPatchType(name, customAttributes);
			if (!type.HasValue)
			{
				return Enumerable.Empty<AttributePatch>();
			}
			if (type != HarmonyPatchType.ReversePatch && !patch.IsStatic)
			{
				throw new ArgumentException("Patch method " + patch.FullDescription() + " must be static");
			}
			List<HarmonyMethod> list = (from attr in customAttributes
				where attr.GetType().BaseType.FullName == harmonyAttributeName
				select AccessTools.Field(attr.GetType(), "info").GetValue(attr) into harmonyInfo
				select AccessTools.MakeDeepCopy<HarmonyMethod>(harmonyInfo)).ToList();
			List<HarmonyMethod> list2 = new List<HarmonyMethod>();
			ILookup<bool, HarmonyMethod> lookup = list.ToLookup((HarmonyMethod m) => IsComplete(m, collectIncomplete));
			List<HarmonyMethod> incomplete = lookup[false].ToList();
			HarmonyMethod info = HarmonyMethod.Merge(incomplete);
			List<HarmonyMethod> list3 = lookup[true].Where((HarmonyMethod m) => !Same(m, info)).ToList();
			if (list3.Count > 1)
			{
				list2.AddRange(list3.Select((HarmonyMethod m) => HarmonyMethod.Merge(incomplete.AddItem(m))));
			}
			else
			{
				list2.Add(HarmonyMethod.Merge(list));
			}
			foreach (HarmonyMethod item in list2)
			{
				item.method = patch;
			}
			return list2.Select((HarmonyMethod i) => new AttributePatch
			{
				info = i,
				type = type
			}).ToList();
			static bool IsComplete(HarmonyMethod m, bool collectIncomplete)
			{
				if (collectIncomplete || m.GetDeclaringType() != null)
				{
					return m.methodName != null;
				}
				return false;
			}
			static bool Same(HarmonyMethod m1, HarmonyMethod m2)
			{
				if (m1.GetDeclaringType() == m2.GetDeclaringType() && m1.methodName == m2.methodName)
				{
					return m1.GetArgumentList().SequenceEqual(m2.GetArgumentList());
				}
				return false;
			}
		}

		private static HarmonyPatchType? GetPatchType(string methodName, object[] allAttributes)
		{
			HashSet<string> hashSet = new HashSet<string>(from attr in allAttributes
				select attr.GetType().FullName into name
				where name.StartsWith("Harmony")
				select name);
			HarmonyPatchType? result = null;
			HarmonyPatchType[] array = allPatchTypes;
			for (int i = 0; i < array.Length; i++)
			{
				HarmonyPatchType value = array[i];
				string text = value.ToString();
				if (text == methodName || hashSet.Contains("HarmonyLib.Harmony" + text))
				{
					result = value;
					break;
				}
			}
			return result;
		}
	}
	internal class PatchSorter
	{
		private class PatchSortingWrapper : IComparable
		{
			internal readonly HashSet<PatchSortingWrapper> after;

			internal readonly HashSet<PatchSortingWrapper> before;

			internal readonly Patch innerPatch;

			internal PatchSortingWrapper(Patch patch)
			{
				innerPatch = patch;
				before = new HashSet<PatchSortingWrapper>();
				after = new HashSet<PatchSortingWrapper>();
			}

			public int CompareTo(object obj)
			{
				return PatchInfoSerialization.PriorityComparer((obj as PatchSortingWrapper)?.innerPatch, innerPatch.index, innerPatch.priority);
			}

			public override bool Equals(object obj)
			{
				if (obj is PatchSortingWrapper patchSortingWrapper)
				{
					return innerPatch.PatchMethod == patchSortingWrapper.innerPatch.PatchMethod;
				}
				return false;
			}

			public override int GetHashCode()
			{
				return innerPatch.PatchMethod.GetHashCode();
			}

			internal void AddBeforeDependency(IEnumerable<PatchSortingWrapper> dependencies)
			{
				foreach (PatchSortingWrapper dependency in dependencies)
				{
					before.Add(dependency);
					dependency.after.Add(this);
				}
			}

			internal void AddAfterDependency(IEnumerable<PatchSortingWrapper> dependencies)
			{
				foreach (PatchSortingWrapper dependency in dependencies)
				{
					after.Add(dependency);
					dependency.before.Add(this);
				}
			}

			internal void RemoveAfterDependency(PatchSortingWrapper afterNode)
			{
				after.Remove(afterNode);
				afterNode.before.Remove(this);
			}

			internal void RemoveBeforeDependency(PatchSortingWrapper beforeNode)
			{
				before.Remove(beforeNode);
				beforeNode.after.Remove(this);
			}
		}

		internal class PatchDetailedComparer : IEqualityComparer<Patch>
		{
			public bool Equals(Patch x, Patch y)
			{
				if (y != null && x != null && x.owner == y.owner && x.PatchMethod == y.PatchMethod && x.index == y.index && x.priority == y.priority && x.before.Length == y.before.Length && x.after.Length == y.after.Length && x.before.All(((IEnumerable<string>)y.before).Contains<string>))
				{
					return x.after.All(((IEnumerable<string>)y.after).Contains<string>);
				}
				return false;
			}

			public int GetHashCode(Patch obj)
			{
				return obj.GetHashCode();
			}
		}

		private List<PatchSortingWrapper> patches;

		private HashSet<PatchSortingWrapper> handledPatches;

		private List<PatchSortingWrapper> result;

		private List<PatchSortingWrapper> waitingList;

		internal Patch[] sortedPatchArray;

		private readonly bool debug;

		internal PatchSorter(Patch[] patches, bool debug = false)
		{
			this.patches = patches.Select((Patch x) => new PatchSortingWrapper(x)).ToList();
			this.debug = debug;
			foreach (PatchSortingWrapper node in this.patches)
			{
				node.AddBeforeDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.before.Contains(x.innerPatch.owner)));
				node.AddAfterDependency(this.patches.Where((PatchSortingWrapper x) => node.innerPatch.after.Contains(x.innerPatch.owner)));
			}
			this.patches.Sort();
		}

		internal List<MethodInfo> Sort(MethodBase original)
		{
			return (from x in SortAsPatches(original)
				select x.GetMethod(original)).ToList();
		}

		internal Patch[] SortAsPatches(MethodBase original)
		{
			if (sortedPatchArray != null)
			{
				return sortedPatchArray;
			}
			handledPatches = new HashSet<PatchSortingWrapper>();
			waitingList = new List<PatchSortingWrapper>();
			result = new List<PatchSortingWrapper>(patches.Count);
			Queue<PatchSortingWrapper> queue = new Queue<PatchSortingWrapper>(patches);
			while (queue.Count != 0)
			{
				foreach (PatchSortingWrapper item in queue)
				{
					if (item.after.All((PatchSortingWrapper x) => handledPatches.Contains(x)))
					{
						AddNodeToResult(item);
						if (item.before.Count != 0)
						{
							ProcessWaitingList();
						}
					}
					else
					{
						waitingList.Add(item);
					}
				}
				CullDependency();
				queue = new Queue<PatchSortingWrapper>(waitingList);
				waitingList.Clear();
			}
			sortedPatchArray = result.Select((PatchSortingWrapper x) => x.innerPatch).ToArray();
			handledPatches = null;
			waitingList = null;
			patches = null;
			return sortedPatchArray;
		}

		internal bool ComparePatchLists(Patch[] patches)
		{
			if (sortedPatchArray == null)
			{
				Sort(null);
			}
			if (patches != null && sortedPatchArray.Length == patches.Length)
			{
				return sortedPatchArray.All((Patch x) => patches.Contains(x, new PatchDetailedComparer()));
			}
			return false;
		}

		private void CullDependency()
		{
			for (int i = waitingList.Count - 1; i >= 0; i--)
			{
				foreach (PatchSortingWrapper afterNode in waitingList[i].after)
				{
					if (!handledPatches.Contains(afterNode))
					{
						waitingList[i].RemoveAfterDependency(afterNode);
						Logger.Log(Logger.LogChannel.Debug, delegate
						{
							string text = afterNode.innerPatch.PatchMethod.FullDescription();
							string text2 = waitingList[i].innerPatch.PatchMethod.FullDescription();
							return "Breaking dependence between " + text + " and " + text2;
						}, debug);
						return;
					}
				}
			}
		}

		private void ProcessWaitingList()
		{
			int num = waitingList.Count;
			int num2 = 0;
			while (num2 < num)
			{
				PatchSortingWrapper patchSortingWrapper = waitingList[num2];
				if (patchSortingWrapper.after.All(handledPatches.Contains))
				{
					waitingList.Remove(patchSortingWrapper);
					AddNodeToResult(patchSortingWrapper);
					num--;
					num2 = 0;
				}
				else
				{
					num2++;
				}
			}
		}

		private void AddNodeToResult(PatchSortingWrapper node)
		{
			result.Add(node);
			handledPatches.Add(node);
		}
	}
	internal static class PatchTools
	{
		[ThreadStatic]
		private static Dictionary<object, object> objectReferences;

		internal static void RememberObject(object key, object value)
		{
			if (objectReferences == null)
			{
				objectReferences = new Dictionary<object, object>();
			}
			objectReferences[key] = value;
		}

		internal static MethodInfo GetPatchMethod(Type patchType, string attributeName)
		{
			MethodInfo methodInfo = patchType.GetMethods(AccessTools.all).FirstOrDefault((MethodInfo m) => m.GetCustomAttributes(inherit: true).Any((object a) => a.GetType().FullName == attributeName));
			if ((object)methodInfo == null)
			{
				string name = attributeName.Replace("HarmonyLib.Harmony", "");
				methodInfo = patchType.GetMethod(name, AccessTools.all);
			}
			return methodInfo;
		}

		internal static AssemblyBuilder DefineDynamicAssembly(string name)
		{
			return AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.Run);
		}

		internal static List<AttributePatch> GetPatchMethods(Type type, bool collectIncomplete = false)
		{
			return (from attributePatch in AccessTools.GetDeclaredMethods(type).SelectMany((MethodInfo m) => AttributePatch.Create(m, collectIncomplete))
				where attributePatch != null
				select attributePatch).ToList();
		}

		internal static MethodBase GetOriginalMethod(this HarmonyMethod attr)
		{
			try
			{
				MethodType? methodType = attr.methodType;
				if (methodType.HasValue)
				{
					switch (methodType.GetValueOrDefault())
					{
					case MethodType.Normal:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes);
					case MethodType.Getter:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetGetMethod(nonPublic: true);
					case MethodType.Setter:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.DeclaredProperty(attr.GetDeclaringType(), attr.methodName).GetSetMethod(nonPublic: true);
					case MethodType.Constructor:
						return AccessTools.DeclaredConstructor(attr.GetDeclaringType(), attr.argumentTypes);
					case MethodType.StaticConstructor:
						return AccessTools.GetDeclaredConstructors(attr.GetDeclaringType()).FirstOrDefault((ConstructorInfo c) => c.IsStatic);
					case MethodType.Enumerator:
						if (attr.methodName == null)
						{
							return null;
						}
						return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes));
					}
				}
			}
			catch (AmbiguousMatchException ex)
			{
				throw new HarmonyException("Ambiguous match for HarmonyMethod[" + attr.Description() + "]", ex.InnerException ?? ex);
			}
			return null;
		}
	}
	public enum MethodType
	{
		Normal,
		Getter,
		Setter,
		Constructor,
		StaticConstructor,
		Enumerator
	}
	public enum ArgumentType
	{
		Normal,
		Ref,
		Out,
		Pointer
	}
	public enum HarmonyPatchType
	{
		All,
		Prefix,
		Postfix,
		Transpiler,
		Finalizer,
		ReversePatch,
		ILManipulator
	}
	public enum HarmonyReversePatchType
	{
		Original,
		Snapshot
	}
	public enum MethodDispatchType
	{
		VirtualCall,
		Call
	}
	[MeansImplicitUse]
	public class HarmonyAttribute : Attribute
	{
		public HarmonyMethod info = new HarmonyMethod();
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Delegate, AllowMultiple = true)]
	public class HarmonyPatch : HarmonyAttribute
	{
		public HarmonyPatch()
		{
		}

		public HarmonyPatch(Type declaringType)
		{
			info.declaringType = declaringType;
		}

		public HarmonyPatch(Type declaringType, Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, string methodName)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
		}

		public HarmonyPatch(Type declaringType, string methodName, params Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string typeName, string methodName)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
		}

		public HarmonyPatch(string typeName, string methodName, MethodType methodType, Type[] argumentTypes = null, ArgumentType[] argumentVariations = null)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
			info.methodType = methodType;
			if (argumentTypes != null)
			{
				ParseSpecialArguments(argumentTypes, argumentVariations);
			}
		}

		public HarmonyPatch(Type declaringType, MethodType methodType)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
		}

		public HarmonyPatch(Type declaringType, MethodType methodType, params Type[] argumentTypes)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type declaringType, MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.declaringType = declaringType;
			info.methodType = methodType;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(Type declaringType, string methodName, MethodType methodType)
		{
			info.declaringType = declaringType;
			info.methodName = methodName;
			info.methodType = methodType;
		}

		public HarmonyPatch(string methodName)
		{
			info.methodName = methodName;
		}

		public HarmonyPatch(string methodName, params Type[] argumentTypes)
		{
			info.methodName = methodName;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.methodName = methodName;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string methodName, MethodType methodType)
		{
			info.methodName = methodName;
			info.methodType = methodType;
		}

		public HarmonyPatch(MethodType methodType)
		{
			info.methodType = methodType;
		}

		public HarmonyPatch(MethodType methodType, params Type[] argumentTypes)
		{
			info.methodType = methodType;
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(MethodType methodType, Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			info.methodType = methodType;
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(Type[] argumentTypes)
		{
			info.argumentTypes = argumentTypes;
		}

		public HarmonyPatch(Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			ParseSpecialArguments(argumentTypes, argumentVariations);
		}

		public HarmonyPatch(string typeName, string methodName, MethodType methodType = MethodType.Normal)
		{
			info.declaringType = AccessTools.TypeByName(typeName);
			info.methodName = methodName;
			info.methodType = methodType;
		}

		private void ParseSpecialArguments(Type[] argumentTypes, ArgumentType[] argumentVariations)
		{
			if (argumentVariations == null || argumentVariations.Length == 0)
			{
				info.argumentTypes = argumentTypes;
				return;
			}
			if (argumentTypes.Length < argumentVariations.Length)
			{
				throw new ArgumentException("argumentVariations contains more elements than argumentTypes", "argumentVariations");
			}
			List<Type> list = new List<Type>();
			for (int i = 0; i < argumentTypes.Length; i++)
			{
				Type type = argumentTypes[i];
				switch (argumentVariations[i])
				{
				case ArgumentType.Ref:
				case ArgumentType.Out:
					type = type.MakeByRefType();
					break;
				case ArgumentType.Pointer:
					type = type.MakePointerType();
					break;
				}
				list.Add(type);
			}
			info.argumentTypes = list.ToArray();
		}
	}
	[AttributeUsage(AttributeTargets.Delegate, AllowMultiple = true)]
	public class HarmonyDelegate : HarmonyPatch
	{
		public HarmonyDelegate(Type declaringType)
			: base(declaringType)
		{
		}

		public HarmonyDelegate(Type declaringType, Type[] argumentTypes)
			: base(declaringType, argumentTypes)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName)
			: base(declaringType, methodName)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName, params Type[] argumentTypes)
			: base(declaringType, methodName, argumentTypes)
		{
		}

		public HarmonyDelegate(Type declaringType, string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(declaringType, methodName, argumentTypes, argumentVariations)
		{
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType)
			: base(declaringType, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, params Type[] argumentTypes)
			: base(declaringType, MethodType.Normal, argumentTypes)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(declaringType, MethodType.Normal, argumentTypes, argumentVariations)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type declaringType, string methodName, MethodDispatchType methodDispatchType)
			: base(declaringType, methodName, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(string methodName)
			: base(methodName)
		{
		}

		public HarmonyDelegate(string methodName, params Type[] argumentTypes)
			: base(methodName, argumentTypes)
		{
		}

		public HarmonyDelegate(string methodName, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(methodName, argumentTypes, argumentVariations)
		{
		}

		public HarmonyDelegate(string methodName, MethodDispatchType methodDispatchType)
			: base(methodName, MethodType.Normal)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType, params Type[] argumentTypes)
			: base(MethodType.Normal, argumentTypes)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(MethodDispatchType methodDispatchType, Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(MethodType.Normal, argumentTypes, argumentVariations)
		{
			info.nonVirtualDelegate = methodDispatchType == MethodDispatchType.Call;
		}

		public HarmonyDelegate(Type[] argumentTypes)
			: base(argumentTypes)
		{
		}

		public HarmonyDelegate(Type[] argumentTypes, ArgumentType[] argumentVariations)
			: base(argumentTypes, argumentVariations)
		{
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
	public class HarmonyReversePatch : HarmonyAttribute
	{
		public HarmonyReversePatch(HarmonyReversePatchType type = HarmonyReversePatchType.Original)
		{
			info.reversePatchType = type;
		}
	}
	[AttributeUsage(AttributeTargets.Class)]
	public class HarmonyPatchAll : HarmonyAttribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyPriority : HarmonyAttribute
	{
		public HarmonyPriority(int priority)
		{
			info.priority = priority;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyBefore : HarmonyAttribute
	{
		public HarmonyBefore(params string[] before)
		{
			info.before = before;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyAfter : HarmonyAttribute
	{
		public HarmonyAfter(params string[] after)
		{
			info.after = after;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyDebug : HarmonyAttribute
	{
		public HarmonyDebug()
		{
			info.debug = true;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyEmitIL : HarmonyAttribute
	{
		public HarmonyEmitIL()
		{
			info.debugEmitPath = "./";
		}

		public HarmonyEmitIL(string dir)
		{
			info.debugEmitPath = dir;
		}
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public class HarmonyWrapSafe : HarmonyAttribute
	{
		public HarmonyWrapSafe()
		{
			info.wrapTryCatch = true;
		}
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPrepare : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyCleanup : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTargetMethod : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTargetMethods : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPrefix : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyPostfix : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyTranspiler : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyILManipulator : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Method)]
	public class HarmonyFinalizer : Attribute
	{
	}
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
	public class HarmonyArgument : Attribute
	{
		public string OriginalName { get; private set; }

		public int Index { get; private set; }

		public string NewName { get; private set; }

		public HarmonyArgument(string originalName)
			: this(originalName, null)
		{
		}

		public HarmonyArgument(int index)
			: this(index, null)
		{
		}

		public HarmonyArgument(string originalName, string newName)
		{
			OriginalName = originalName;
			Index = -1;
			NewName = newName;
		}

		public HarmonyArgument(int index, string name)
		{
			OriginalName = null;
			Index = index;
			NewName = name;
		}
	}
	public class CodeInstruction
	{
		public OpCode opcode;

		public object operand;

		public List<Label> labels = new List<Label>();

		public List<ExceptionBlock> blocks = new List<ExceptionBlock>();

		internal CodeInstruction()
		{
		}

		public CodeInstruction(OpCode opcode, object operand = null)
		{
			this.opcode = opcode;
			this.operand = operand;
		}

		public CodeInstruction(CodeInstruction instruction)
		{
			opcode = instruction.opcode;
			operand = instruction.operand;
			labels = instruction.labels.ToList();
			blocks = instruction.blocks.ToList();
		}

		public CodeInstruction Clone()
		{
			return new CodeInstruction(this)
			{
				labels = new List<Label>(),
				blocks = new List<ExceptionBlock>()
			};
		}

		public CodeInstruction Clone(OpCode opcode)
		{
			CodeInstruction codeInstruction = Clone();
			codeInstruction.opcode = opcode;
			return codeInstruction;
		}

		public CodeInstruction Clone(object operand)
		{
			CodeInstruction codeInstruction = Clone();
			codeInstruction.operand = operand;
			return codeInstruction;
		}

		public static CodeInstruction Call(Type type, string name, Type[] parameters = null, Type[] generics = null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, name, parameters, generics);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException($"No method found for type={type}, name={name}, parameters={parameters.Description()}, generics={generics.Description()}");
			}
			return new CodeInstruction(OpCodes.Call, methodInfo);
		}

		public static CodeInstruction Call(string typeColonMethodname, Type[] parameters = null, Type[] generics = null)
		{
			MethodInfo methodInfo = AccessTools.Method(typeColonMethodname, parameters, generics);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException("No method found for " + typeColonMethodname + ", parameters=" + parameters.Description() + ", generics=" + generics.Description());
			}
			return new CodeInstruction(OpCodes.Call, methodInfo);
		}

		public static CodeInstruction Call(Expression<Action> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call<T>(Expression<Action<T>> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call<T, TResult>(Expression<Func<T, TResult>> expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction Call(LambdaExpression expression)
		{
			return new CodeInstruction(OpCodes.Call, SymbolExtensions.GetMethodInfo(expression));
		}

		public static CodeInstruction CallClosure<T>(T closure) where T : Delegate
		{
			return Transpilers.EmitDelegate(closure);
		}

		public static CodeInstruction LoadField(Type type, string name, bool useAddress = false)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if ((object)fieldInfo == null)
			{
				throw new ArgumentException($"No field found for {type} and {name}");
			}
			return new CodeInstruction((!useAddress) ? (fieldInfo.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld) : (fieldInfo.IsStatic ? OpCodes.Ldsflda : OpCodes.Ldflda), fieldInfo);
		}

		public static CodeInstruction StoreField(Type type, string name)
		{
			FieldInfo fieldInfo = AccessTools.Field(type, name);
			if ((object)fieldInfo == null)
			{
				throw new ArgumentException($"No field found for {type} and {name}");
			}
			return new CodeInstruction(fieldInfo.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fieldInfo);
		}

		public override string ToString()
		{
			List<string> list = new List<string>();
			foreach (Label label in labels)
			{
				list.Add($"Label{label.GetHashCode()}");
			}
			foreach (ExceptionBlock block in blocks)
			{
				list.Add("EX_" + block.blockType.ToString().Replace("Block", ""));
			}
			string text = ((list.Count > 0) ? (" [" + string.Join(", ", list.ToArray()) + "]") : "");
			string text2 = FormatArgument(operand);
			if (text2.Length > 0)
			{
				text2 = " " + text2;
			}
			OpCode opCode = opcode;
			return opCode.ToString() + text2 + text;
		}

		internal static string FormatArgument(object argument, string extra = null)
		{
			if (argument == null)
			{
				return "NULL";
			}
			Type type = argument.GetType();
			if (argument is MethodBase member)
			{
				return member.FullDescription() + ((extra != null) ? (" " + extra) : "");
			}
			if (argument is FieldInfo fieldInfo)
			{
				return fieldInfo.FieldType.FullDescription() + " " + fieldInfo.DeclaringType.FullDescription() + "::" + fieldInfo.Name;
			}
			if (type == typeof(Label))
			{
				return $"Label{((Label)argument).GetHashCode()}";
			}
			if (type == typeof(Label[]))
			{
				return "Labels" + string.Join(",", ((Label[])argument).Select((Label l) => l.GetHashCode().ToString()).ToArray());
			}
			if (type == typeof(LocalBuilder))
			{
				return $"{((LocalBuilder)argument).LocalIndex} ({((LocalBuilder)argument).LocalType})";
			}
			if (type == typeof(string))
			{
				return argument.ToString().ToLiteral();
			}
			return argument.ToString().Trim();
		}
	}
	public enum ExceptionBlockType
	{
		BeginExceptionBlock,
		BeginCatchBlock,
		BeginExceptFilterBlock,
		BeginFaultBlock,
		BeginFinallyBlock,
		EndExceptionBlock
	}
	public class ExceptionBlock
	{
		public ExceptionBlockType blockType;

		public Type catchType;

		public ExceptionBlock(ExceptionBlockType blockType, Type catchType = null)
		{
			this.blockType = blockType;
			this.catchType = catchType ?? typeof(object);
		}
	}
	public class InvalidHarmonyPatchArgumentException : Exception
	{
		public MethodBase Original { get; }

		public MethodInfo Patch { get; }

		public override string Message => "(" + Patch.FullDescription() + "): " + base.Message;

		public InvalidHarmonyPatchArgumentException(string message, MethodBase original, MethodInfo patch)
			: base(message)
		{
			Original = original;
			Patch = patch;
		}
	}
	public class MemberNotFoundException : Exception
	{
		public MemberNotFoundException(string message)
			: base(message)
		{
		}
	}
	public class Harmony : IDisposable
	{
		[Obsolete("Use HarmonyFileLog.Enabled instead")]
		public static bool DEBUG;

		public string Id { get; }

		static Harmony()
		{
			StackTraceFixes.Install();
		}

		public Harmony(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				throw new ArgumentException("id cannot be null or empty");
			}
			try
			{
				string environmentVariable = Environment.GetEnvironmentVariable("HARMONY_DEBUG");
				if (environmentVariable != null && environmentVariable.Length > 0)
				{
					environmentVariable = environmentVariable.Trim();
					DEBUG = environmentVariable == "1" || bool.Parse(environmentVariable);
				}
			}
			catch
			{
			}
			if (DEBUG)
			{
				HarmonyFileLog.Enabled = true;
			}
			MethodBase callingMethod = (Logger.IsEnabledFor(Logger.LogChannel.Info) ? AccessTools.GetOutsideCaller() : null);
			Logger.Log(Logger.LogChannel.Info, delegate
			{
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0075: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				StringBuilder stringBuilder = new StringBuilder();
				Assembly assembly = typeof(Harmony).Assembly;
				Version version = assembly.GetName().Version;
				string text = assembly.Location;
				string text2 = Environment.Version.ToString();
				string text3 = Environment.OSVersion.Platform.ToString();
				if (string.IsNullOrEmpty(text))
				{
					text = new Uri(assembly.CodeBase).LocalPath;
				}
				int size = IntPtr.Size;
				Platform current = PlatformHelper.Current;
				stringBuilder.AppendLine($"### Harmony id={id}, version={version}, location={text}, env/clr={text2}, platform={text3}, ptrsize:runtime/env={size}/{current}");
				if ((object)callingMethod?.DeclaringType != null)
				{
					Assembly assembly2 = callingMethod.DeclaringType.Assembly;
					text = assembly2.Location;
					if (string.IsNullOrEmpty(text))
					{
						text = new Uri(assembly2.CodeBase).LocalPath;
					}
					stringBuilder.AppendLine("### Started from " + callingMethod.FullDescription() + ", location " + text);
					stringBuilder.Append($"### At {DateTime.Now:yyyy-MM-dd hh.mm.ss}");
				}
				return stringBuilder.ToString();
			});
			Id = id;
		}

		public void PatchAll()
		{
			Assembly assembly = new StackTrace().GetFrame(1).GetMethod().ReflectedType.Assembly;
			PatchAll(assembly);
		}

		public PatchProcessor CreateProcessor(MethodBase original)
		{
			return new PatchProcessor(this, original);
		}

		public PatchClassProcessor CreateClassProcessor(Type type)
		{
			return new PatchClassProcessor(this, type);
		}

		public PatchClassProcessor CreateClassProcessor(Type type, bool allowUnannotatedType)
		{
			return new PatchClassProcessor(this, type, allowUnannotatedType);
		}

		public ReversePatcher CreateReversePatcher(MethodBase original, HarmonyMethod standin)
		{
			return new ReversePatcher(this, original, standin);
		}

		public void PatchAll(Assembly assembly)
		{
			AccessTools.GetTypesFromAssembly(assembly).Do(delegate(Type type)
			{
				CreateClassProcessor(type).Patch();
			});
		}

		public void PatchAll(Type type)
		{
			CreateClassProcessor(type, allowUnannotatedType: true).Patch();
		}

		public MethodInfo Patch(MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null, HarmonyMethod finalizer = null, HarmonyMethod ilmanipulator = null)
		{
			PatchProcessor patchProcessor = CreateProcessor(original);
			patchProcessor.AddPrefix(prefix);
			patchProcessor.AddPostfix(postfix);
			patchProcessor.AddTranspiler(transpiler);
			patchProcessor.AddFinalizer(finalizer);
			patchProcessor.AddILManipulator(ilmanipulator);
			return patchProcessor.Patch();
		}

		[Obsolete("Use newer Patch() instead", true)]
		public MethodInfo Patch(MethodBase original, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer)
		{
			return Patch(original, prefix, postfix, transpiler, finalizer, null);
		}

		public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler = null, MethodInfo ilmanipulator = null)
		{
			return PatchFunctions.ReversePatch(standin, original, transpiler, ilmanipulator);
		}

		[Obsolete("Use newer ReversePatch() instead", true)]
		public static MethodInfo ReversePatch(MethodBase original, HarmonyMethod standin, MethodInfo transpiler)
		{
			return PatchFunctions.ReversePatch(standin, original, transpiler, null);
		}

		public static void UnpatchID(string harmonyID)
		{
			if (string.IsNullOrEmpty(harmonyID))
			{
				throw new ArgumentNullException("harmonyID", "UnpatchID was called with a null or empty harmonyID.");
			}
			PatchFunctions.UnpatchConditional((Patch patchInfo) => patchInfo.owner == harmonyID);
		}

		void IDisposable.Dispose()
		{
			UnpatchSelf();
		}

		public void UnpatchSelf()
		{
			UnpatchID(Id);
		}

		public static void UnpatchAll()
		{
			Logger.Log(Logger.LogChannel.Warn, () => "UnpatchAll has been called - This will remove ALL HARMONY PATCHES.");
			PatchFunctions.UnpatchConditional((Patch _) => true);
		}

		[Obsolete("Use UnpatchSelf() to unpatch the current instance. The functionality to unpatch either other ids or EVERYTHING has been moved the static methods UnpatchID() and UnpatchAll() respectively", true)]
		public void UnpatchAll(string harmonyID = null)
		{
			if (harmonyID == null)
			{
				if (HarmonyGlobalSettings.DisallowLegacyGlobalUnpatchAll)
				{
					Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll has been called AND DisallowLegacyGlobalUnpatchAll=true. Skipping execution of UnpatchAll");
				}
				else
				{
					UnpatchAll();
				}
			}
			else if (harmonyID.Length == 0)
			{
				Logger.Log(Logger.LogChannel.Warn, () => "Legacy UnpatchAll was called with harmonyID=\"\" which is an invalid id. Skipping execution of UnpatchAll");
			}
			else
			{
				UnpatchID(harmonyID);
			}
		}

		public void Unpatch(MethodBase original, HarmonyPatchType type, string harmonyID = "*")
		{
			CreateProcessor(original).Unpatch(type, harmonyID);
		}

		public void Unpatch(MethodBase original, MethodInfo patch)
		{
			CreateProcessor(original).Unpatch(patch);
		}

		public static bool HasAnyPatches(string harmonyID)
		{
			return (from original in GetAllPatchedMethods()
				select GetPatchInfo(original)).Any((Patches info) => info.Owners.Contains(harmonyID));
		}

		public static Patches GetPatchInfo(MethodBase method)
		{
			return PatchProcessor.GetPatchInfo(method);
		}

		public IEnumerable<MethodBase> GetPatchedMethods()
		{
			return from original in GetAllPatchedMethods()
				where GetPatchInfo(original).Owners.Contains(Id)
				select original;
		}

		public static IEnumerable<MethodBase> GetAllPatchedMethods()
		{
			return PatchProcessor.GetAllPatchedMethods();
		}

		public static MethodBase GetOriginalMethod(MethodInfo replacement)
		{
			if (replacement == null)
			{
				throw new ArgumentNullException("replacement");
			}
			return PatchManager.GetOriginal(replacement);
		}

		public static MethodBase GetMethodFromStackframe(StackFrame frame)
		{
			if (frame == null)
			{
				throw new ArgumentNullException("frame");
			}
			return PatchManager.FindReplacement(frame) ?? frame.GetMethod();
		}

		public static MethodBase GetOriginalMethodFromStackframe(StackFrame frame)
		{
			MethodBase methodBase = GetMethodFromStackframe(frame);
			if (methodBase is MethodInfo replacement)
			{
				methodBase = GetOriginalMethod(replacement) ?? methodBase;
			}
			return methodBase;
		}

		public static Dictionary<string, Version> VersionInfo(out Version currentVersion)
		{
			return PatchProcessor.VersionInfo(out currentVersion);
		}

		public static Harmony CreateAndPatchAll(Type type, string harmonyInstanceId = null)
		{
			Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}");
			harmony.PatchAll(type);
			return harmony;
		}

		public static Harmony CreateAndPatchAll(Assembly assembly, string harmonyInstanceId = null)
		{
			Harmony harmony = new Harmony(harmonyInstanceId ?? $"harmony-auto-{Guid.NewGuid()}");
			harmony.PatchAll(assembly);
			return harmony;
		}
	}
	[Serializable]
	public class HarmonyException : Exception
	{
		private Dictionary<int, CodeInstruction> instructions = new Dictionary<int, CodeInstruction>();

		private int errorOffset = -1;

		internal HarmonyException()
		{
		}

		internal HarmonyException(string message)
			: base(message)
		{
		}

		internal HarmonyException(string message, Exception innerException)
			: base(message, innerException)
		{
		}

		protected HarmonyException(SerializationInfo serializationInfo, StreamingContext streamingContext)
		{
			throw new NotImplementedException();
		}

		internal HarmonyException(Exception innerException, Dictionary<int, CodeInstruction> instructions, int errorOffset)
			: base("IL Compile Error", innerException)
		{
			this.instructions = instructions;
			this.errorOffset = errorOffset;
		}

		internal static Exception Create(Exception ex, MethodBody body)
		{
			if (ex is HarmonyException ex2)
			{
				Dictionary<int, CodeInstruction> dictionary = ex2.instructions;
				if (dictionary != null && dictionary.Count > 0 && ex2.errorOffset >= 0)
				{
					return ex;
				}
			}
			Match match = Regex.Match(ex.Message.TrimEnd(Array.Empty<char>()), "(?:Reason: )?Invalid IL code in.+: IL_(\\d{4}): (.+)$");
			if (!match.Success)
			{
				return new HarmonyException("IL Compile Error (unknown location)", ex);
			}
			Dictionary<int, CodeInstruction> dictionary2 = ILManipulator.GetInstructions(body) ?? new Dictionary<int, CodeInstruction>();
			int num = int.Parse(match.Groups[1].Value, NumberStyles.HexNumber);
			Regex.Replace(match.Groups[2].Value, " {2,}", " ");
			if (ex is HarmonyException ex3)
			{
				if (dictionary2.Count != 0)
				{
					ex3.instructions = dictionary2;
					ex3.errorOffset = num;
				}
				return ex3;
			}
			return new HarmonyException(ex, dictionary2, num);
		}

		public List<KeyValuePair<int, CodeInstruction>> GetInstructionsWithOffsets()
		{
			return instructions.OrderBy((KeyValuePair<int, CodeInstruction> ins) => ins.Key).ToList();
		}

		public List<CodeInstruction> GetInstructions()
		{
			return (from ins in instructions
				orderby ins.Key
				select ins.Value).ToList();
		}

		public int GetErrorOffset()
		{
			return errorOffset;
		}

		public int GetErrorIndex()
		{
			if (instructions.TryGetValue(errorOffset, out var value))
			{
				return GetInstructions().IndexOf(value);
			}
			return -1;
		}
	}
	public static class HarmonyGlobalSettings
	{
		public static bool DisallowLegacyGlobalUnpatchAll { get; set; }
	}
	public class HarmonyMethod
	{
		public MethodInfo method;

		public Type declaringType;

		public string methodName;

		public MethodType? methodType;

		public Type[] argumentTypes;

		public int priority = -1;

		public string[] before;

		public string[] after;

		public HarmonyReversePatchType? reversePatchType;

		public bool? debug;

		public string debugEmitPath;

		public bool nonVirtualDelegate;

		public bool? wrapTryCatch;

		public HarmonyMethod()
		{
		}

		private void ImportMethod(MethodInfo theMethod)
		{
			if ((object)theMethod == null)
			{
				throw new ArgumentNullException("theMethod", "Harmony method is null (did you target a wrong or missing method?)");
			}
			if (!theMethod.IsStatic)
			{
				throw new ArgumentException("Harmony method must be static", "theMethod");
			}
			method = theMethod;
			List<HarmonyMethod> fromMethod = HarmonyMethodExtensions.GetFromMethod(method);
			if (fromMethod != null)
			{
				Merge(fromMethod).CopyTo(this);
			}
		}

		public HarmonyMethod(MethodInfo method)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			ImportMethod(method);
		}

		public HarmonyMethod(MethodInfo method, int priority = -1, string[] before = null, string[] after = null, bool? debug = null)
		{
			if ((object)method == null)
			{
				throw new ArgumentNullException("method");
			}
			ImportMethod(method);
			this.priority = priority;
			this.before = before;
			this.after = after;
			this.debug = debug;
		}

		public HarmonyMethod(Type methodType, string methodName, Type[] argumentTypes = null)
		{
			MethodInfo methodInfo = AccessTools.Method(methodType, methodName, argumentTypes);
			if ((object)methodInfo == null)
			{
				throw new ArgumentException($"Cannot not find method for type {methodType} and name {methodName} and parameters {argumentTypes?.Description()}");
			}
			ImportMethod(methodInfo);
		}

		public static List<string> HarmonyFields()
		{
			return (from s in AccessTools.GetFieldNames(typeof(HarmonyMethod))
				where s != "method"
				select s).ToList();
		}

		public static HarmonyMethod Merge(List<HarmonyMethod> attributes)
		{
			return Merge((IEnumerable<HarmonyMethod>)attributes);
		}

		internal static HarmonyMethod Merge(IEnumerable<HarmonyMethod> attributes)
		{
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			if (attributes == null)
			{
				return harmonyMethod;
			}
			Traverse resultTrv = Traverse.Create(harmonyMethod);
			attributes.Do(delegate(HarmonyMethod attribute)
			{
				Traverse trv = Traverse.Create(attribute);
				HarmonyFields().ForEach(delegate(string f)
				{
					object value = trv.Field(f).GetValue();
					if (value != null && (f != "priority" || (int)value != -1))
					{
						HarmonyMethodExtensions.SetValue(resultTrv, f, value);
					}
				});
			});
			return harmonyMethod;
		}

		public override string ToString()
		{
			string result = "";
			Traverse trv = Traverse.Create(this);
			HarmonyFields().ForEach(delegate(string f)
			{
				if (result.Length > 0)
				{
					result += ", ";
				}
				result += $"{f}={trv.Field(f).GetValue()}";
			});
			return "HarmonyMethod[" + result + "]";
		}

		internal string Description()
		{
			string text = (((object)declaringType != null) ? declaringType.FullDescription() : "undefined");
			string text2 = methodName ?? "undefined";
			string text3 = (methodType.HasValue ? methodType.Value.ToString() : "undefined");
			string text4 = ((argumentTypes != null) ? argumentTypes.Description() : "undefined");
			return "(class=" + text + ", methodname=" + text2 + ", type=" + text3 + ", args=" + text4 + ")";
		}

		internal Type GetDeclaringType()
		{
			return declaringType;
		}

		internal Type[] GetArgumentList()
		{
			return argumentTypes ?? EmptyType.NoArgs;
		}
	}
	internal static class EmptyType
	{
		internal static readonly Type[] NoArgs = new Type[0];
	}
	public static class HarmonyMethodExtensions
	{
		internal static void SetValue(Traverse trv, string name, object val)
		{
			if (val != null)
			{
				Traverse traverse = trv.Field(name);
				if (name == "methodType" || name == "reversePatchType")
				{
					val = Enum.ToObject(Nullable.GetUnderlyingType(traverse.GetValueType()), (int)val);
				}
				traverse.SetValue(val);
			}
		}

		public static void CopyTo(this HarmonyMethod from, HarmonyMethod to)
		{
			if (to == null)
			{
				return;
			}
			Traverse fromTrv = Traverse.Create(from);
			Traverse toTrv = Traverse.Create(to);
			HarmonyMethod.HarmonyFields().ForEach(delegate(string f)
			{
				object value = fromTrv.Field(f).GetValue();
				if (value != null)
				{
					SetValue(toTrv, f, value);
				}
			});
		}

		public static HarmonyMethod Clone(this HarmonyMethod original)
		{
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			original.CopyTo(harmonyMethod);
			return harmonyMethod;
		}

		public static HarmonyMethod Merge(this HarmonyMethod master, HarmonyMethod detail)
		{
			if (detail == null)
			{
				return master;
			}
			HarmonyMethod harmonyMethod = new HarmonyMethod();
			Traverse resultTrv = Traverse.Create(harmonyMethod);
			Traverse masterTrv = Traverse.Create(master);
			Traverse detailTrv = Traverse.Create(detail);
			HarmonyMethod.HarmonyFields().ForEach(delegate(string f)
			{
				object value = masterTrv.Field(f).GetValue();
				object value2 = detailTrv.Field(f).GetValue();
				if (f != "priority" || (int)value2 != -1)
				{
					SetValue(resultTrv, f, value2 ?? value);
				}
			});
			return harmonyMethod;
		}

		private static HarmonyMethod GetHarmonyMethodInfo(object attribute)
		{
			FieldInfo field = attribute.GetType().GetField("info", AccessTools.all);
			if ((object)field == null)
			{
				return null;
			}
			if (field.FieldType.FullName != typeof(HarmonyMethod).FullName)
			{
				return null;
			}
			return AccessTools.MakeDeepCopy<HarmonyMethod>(field.GetValue(attribute));
		}

		public static List<HarmonyMethod> GetFromType(Type type)
		{
			return (from attr in type.GetCustomAttributes(inherit: true)
				select GetHarmonyMethodInfo(attr) into info
				where info != null
				select info).ToList();
		}

		public static HarmonyMethod GetMergedFromType(Type type)
		{
			return HarmonyMethod.Merge(GetFromType(type));
		}

		public static List<HarmonyMethod> GetFromMethod(MethodBase method)
		{
			return (from attr in method.GetCustomAttributes(inherit: true)
				select GetHarmonyMethodInfo(attr) into info
				where info != null
				select info).ToList();
		}

		public static HarmonyMethod GetMergedFromMethod(MethodBase method)
		{
			return HarmonyMethod.Merge(GetFromMethod(method));
		}
	}
	public class InlineSignature : ICallSiteGenerator
	{
		public class ModifierType
		{
			public bool IsOptional;

			public Type Modifier;

			public object Type;

			public override string ToString()
			{
				return ((Type is Type type) ? type.FullDescription() : Type?.ToString()) + " mod" + (IsOptional ? "opt" : "req") + "(" + Modifier?.FullDescription() + ")";
			}

			internal TypeReference ToTypeReference(ModuleDefinition module)
			{
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Expected O, but got Unknown
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Expected O, but got Unknown
				if (!IsOptional)
				{
					return (TypeReference)new RequiredModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type));
				}
				return (TypeReference)new OptionalModifierType(module.ImportReference(Modifier), GetTypeReference(module, Type));
			}
		}

		public bool HasThis { get; set; }

		public bool ExplicitThis { get; set; }

		public CallingConvention CallingConvention { get; set; } = CallingConvention.Winapi;


		public List<object> Parameters { get; set; } = new List<object>();


		public object ReturnType { get; set; } = typeof(void);


		public override string ToString()
		{
			return ((ReturnType is Type type) ? type.FullDescription() : ReturnType?.ToString()) + " (" + Parameters.Join((object p) => (!(p is Type type2)) ? p?.ToString() : type2.FullDescription()) + ")";
		}

		internal static TypeReference GetTypeReference(ModuleDefinition module, object param)
		{
			if (!(param is Type type))
			{
				if (!(param is InlineSignature inlineSignature))
				{
					if (param is ModifierType modifierType)
					{
						return modifierType.ToTypeReference(module);
					}
					throw new NotSupportedException($"Unsupported inline signature parameter type: {param} ({param?.GetType().FullDescription()})");
				}
				return (TypeReference)(object)inlineSignature.ToFunctionPointer(module);
			}
			return module.ImportReference(type);
		}

		CallSite ICallSiteGenerator.ToCallSite(ModuleDefinition module)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			CallSite val = new CallSite(GetTypeReference(module, ReturnType))
			{
				HasThis = HasThis,
				ExplicitThis = ExplicitThis,
				CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1)
			};
			foreach (object parameter in Parameters)
			{
				val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter)));
			}
			return val;
		}

		private FunctionPointerType ToFunctionPointer(ModuleDefinition module)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			FunctionPointerType val = new FunctionPointerType
			{
				ReturnType = GetTypeReference(module, ReturnType),
				HasThis = HasThis,
				ExplicitThis = ExplicitThis,
				CallingConvention = (MethodCallingConvention)(byte)((byte)CallingConvention - 1)
			};
			foreach (object parameter in Parameters)
			{
				val.Parameters.Add(new ParameterDefinition(GetTypeReference(module, parameter)));
			}
			return val;
		}
	}
	internal static class PatchInfoSerialization
	{
		private class Binder : SerializationBinder
		{
			public override Type BindToType(string assemblyName, string typeName)
			{
				Type[] array = new Type[3]
				{
					typeof(PatchInfo),
					typeof(Patch[]),
					typeof(Patch)
				};
				foreach (Type type in array)
				{
					if (typeName == type.FullName)
					{
						return type;
					}
				}
				return Type.GetType($"{typeName}, {assemblyName}");
			}
		}

		internal static byte[] Serialize(this PatchInfo patchInfo)
		{
			using MemoryStream memoryStream = new MemoryStream();
			new BinaryFormatter().Serialize(memoryStream, patchInfo);
			return memoryStream.GetBuffer();
		}

		internal static PatchInfo Deserialize(byte[] bytes)
		{
			BinaryFormatter obj = new BinaryFormatter
			{
				Binder = new Binder()
			};
			MemoryStream serializationStream = new MemoryStream(bytes);
			return (PatchInfo)obj.Deserialize(serializationStream);
		}

		internal static int PriorityComparer(object obj, int index, int priority)
		{
			Traverse traverse = Traverse.Create(obj);
			int value = traverse.Field("priority").GetValue<int>();
			int value2 = traverse.Field("index").GetValue<int>();
			if (priority != value)
			{
				return -priority.CompareTo(value);
			}
			return index.CompareTo(value2);
		}
	}
	[Serializable]
	public class PatchInfo
	{
		public Patch[] prefixes = new Patch[0];

		public Patch[] postfixes = new Patch[0];

		public Patch[] transpilers = new Patch[0];

		public Patch[] finalizers = new Patch[0];

		public Patch[] ilmanipulators = new Patch[0];

		public bool Debugging
		{
			get
			{
				if (!prefixes.Any((Patch p) => p.debug) && !postfixes.Any((Patch p) => p.debug) && !transpilers.Any((Patch p) => p.debug) && !finalizers.Any((Patch p) => p.debug))
				{
					return ilmanipulators.Any((Patch p) => p.debug);
				}
				return true;
			}
		}

		public string[] DebugEmitPaths => (from p in prefixes.Concat(postfixes).Concat(transpilers).Concat(finalizers)
				.Concat(ilmanipulators)
			select p.debugEmitPath into p
			where p != null
			select p).ToArray();

		internal void AddPrefixes(string owner, params HarmonyMethod[] methods)
		{
			prefixes = Add(owner, methods, prefixes);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddPrefix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddPrefixes(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemovePrefix(string owner)
		{
			prefixes = Remove(owner, prefixes);
		}

		internal void AddPostfixes(string owner, params HarmonyMethod[] methods)
		{
			postfixes = Add(owner, methods, postfixes);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddPostfix(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddPostfixes(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemovePostfix(string owner)
		{
			postfixes = Remove(owner, postfixes);
		}

		internal void AddTranspilers(string owner, params HarmonyMethod[] methods)
		{
			transpilers = Add(owner, methods, transpilers);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddTranspiler(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddTranspilers(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemoveTranspiler(string owner)
		{
			transpilers = Remove(owner, transpilers);
		}

		internal void AddFinalizers(string owner, params HarmonyMethod[] methods)
		{
			finalizers = Add(owner, methods, finalizers);
		}

		[Obsolete("This method only exists for backwards compatibility since the class is public.")]
		public void AddFinalizer(MethodInfo patch, string owner, int priority, string[] before, string[] after, bool debug)
		{
			AddFinalizers(owner, new HarmonyMethod(patch, priority, before, after, debug));
		}

		public void RemoveFinalizer(string owner)
		{
			finalizers = Remove(owner, finalizers);
		}

		internal void AddILManipulators(string owner, params HarmonyMethod[] methods)
		{
			ilmanipulators = Add(owner, methods, ilmanipulators);
		}

		public void RemoveILManipulator(string owner)
		{
			ilmanipulators = Remove(owner, ilmanipulators);
		}

		public void RemovePatch(MethodInfo patch)
		{
			prefixes = prefixes.Where((Patch p) => p.PatchMethod != patch).ToArray();
			postfixes = postfixes.Where((Patch p) => p.PatchMethod != patch).ToArray();
			transpilers = transpilers.Where((Patch p) => p.PatchMethod != patch).ToArray();
			finalizers = finalizers.Where((Patch p) => p.PatchMethod != patch).ToArray();
			ilmanipulators = ilmanipulators.Where((Patch p) => p.PatchMethod != patch).ToArray();
		}

		private static Patch[] Add(string owner, HarmonyMethod[] add, Patch[] current)
		{
			if (add.Length == 0)
			{
				return current;
			}
			int initialIndex = current.Length;
			return current.Concat(add.Where((HarmonyMethod method) => method != null).Select((HarmonyMethod method, int i) => new Patch(method, i + initialIndex, owner))).ToArray();
		}

		private static Patch[] Remove(string owner, Patch[] current)
		{
			if (!(owner == "*"))
			{
				return current.Where((Patch patch) => patch.owner != owner).ToArray();
			}
			return new Patch[0];
		}
	}
	[Serializable]
	public class Patch : IComparable
	{
		public readonly int index;

		public readonly string owner;

		public readonly int priority;

		public readonly string[] before;

		public readonly string[] after;

		public readonly bool debug;

		public readonly string debugEmitPath;

		public readonly bool wrapTryCatch;

		[NonSerialized]
		private MethodInfo patchMethod;

		private int methodToken;

		private string moduleGUID;

		public MethodInfo PatchMethod
		{
			get
			{
				if ((object)patchMethod == null)
				{
					Module module = (from a in AppDomain.CurrentDomain.GetAssemblies()
						where !a.FullName.StartsWith("Microsoft.VisualStudio")
						select a).SelectMany((Assembly a) => a.GetLoadedModules()).First((Module m) => m.ModuleVersionId.ToString() == moduleGUID);
					patchMethod = (MethodInfo)module.ResolveMethod(methodToken);
				}
				return patchMethod;
			}
			set
			{
				patchMethod = value;
				methodToken = patchMethod.MetadataToken;
				moduleGUID = patchMethod.Module.ModuleVersionId.ToString();
			}
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			PatchMethod = patch;
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			this.wrapTryCatch = wrapTryCatch;
			PatchMethod = patch;
		}

		public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug, bool wrapTryCatch, string debugEmitPath)
		{
			if (patch is DynamicMethod)
			{
				throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
			}
			this.index = index;
			this.owner = owner;
			this.priority = ((priority == -1) ? 400 : priority);
			this.before = before ?? new string[0];
			this.after = after ?? new string[0];
			this.debug = debug;
			this.debugEmitPath = debugEmitPath;
			this.wrapTryCatch = wrapTryCatch;
			PatchMethod = patch;
		}

		public Patch(HarmonyMethod method, int index, string owner)
			: this(method.method, index, owner, method.priority, method.before, method.after, method.debug.GetValueOrDefault(), method.wrapTryCatch.GetValueOrDefault(), method.debugEmitPath)
		{
		}

		public MethodInfo GetMethod(MethodBase original)
		{
			MethodInfo methodInfo = PatchMethod;
			if (methodInfo.ReturnType != typeof(DynamicMethod) && methodInfo.ReturnType != typeof(MethodInfo))
			{
				return methodInfo;
			}
			if (!methodInfo.IsStatic)
			{
				return methodInfo;
			}
			ParameterInfo[] parameters = methodInfo.GetParameters();
			if (parameters.Length != 1)
			{
				return methodInfo;
			}
			if (parameters[0].ParameterType != typeof(MethodBase))
			{
				return methodInfo;
			}
			return methodInfo.Invoke(null, new object[1] { original }) as MethodInfo;
		}

		public override bool Equals(object obj)
		{
			if (obj != null && obj is Patch)
			{
				return PatchMethod == ((Patch)obj).PatchMethod;
			}
			return false;
		}

		public int CompareTo(object obj)
		{
			return PatchInfoSerialization.PriorityComparer(obj, index, priority);
		}

		public override int GetHashCode()
		{
			return PatchMethod.GetHashCode();
		}
	}
	public class PatchClassProcessor
	{
		private readonly Harmony instance;

		private readonly Type containerType;

		private readonly HarmonyMethod containerAttributes;

		private readonly Dictionary<Type, MethodInfo> auxilaryMethods;

		private readonly List<AttributePatch> patchMethods;

		private static readonly List<Type> auxilaryTypes = new List<Type>
		{
			typeof(HarmonyPrepare),
			typeof(HarmonyCleanup),
			typeof(HarmonyTargetMethod),
			typeof(HarmonyTargetMethods)
		};

		public PatchClassProcessor(Harmony instance, Type type)
			: this(instance, type, allowUnannotatedType: false)
		{
		}

		public PatchClassProcessor(Harmony instance, Type type, bool allowUnannotatedType)
		{
			if (instance == null)
			{
				throw new ArgumentNullException("instance");
			}
			if ((object)type == null)
			{
				throw new ArgumentNullException("type");
			}
			this.instance = instance;
			containerType = type;
			List<HarmonyMethod> fromType = HarmonyMethodExtensions.GetFromType(type);
			if (!allowUnannotatedType && (fromType == null || fromType.Count == 0))
			{
				return;
			}
			containerAttributes = HarmonyMethod.Merge(fromType);
			MethodType? methodType = containerAttributes.methodType;
			if (!methodType.HasValue)
			{
				containerAttributes.methodType = MethodType.Normal;
			}
			auxilaryMethods = new Dictionary<Type, MethodInfo>();
			foreach (Type auxilaryType in auxilaryTypes)
			{
				MethodInfo patchMethod = PatchTools.GetPatchMethod(containerType, auxilaryType.FullName);
				if ((object)patchMethod != null)
				{
					auxilaryMethods[auxilaryType] = patchMethod;
				}
			}
			patchMethods = PatchTools.GetPatchMethods(containerType, containerAttributes.GetDeclaringType() != null);
			foreach (AttributePatch patchMethod2 in patchMethods)
			{
				MethodInfo method = patchMethod2.info.method;
				patchMethod2.info = containerAttributes.Merge(patchMethod2.info);
				patchMethod2.info.method = method;
			}
		}

		public List<MethodInfo> Patch()
		{
			if (containerAttributes == null)
			{
				return null;
			}
			Exception exception = null;
			if (!RunMethod<HarmonyPrepare, bool>(defaultIfNotExisting: true, defaultIfFailing: false, null, Array.Empty<object>()))
			{
				RunMethod<HarmonyCleanup>(ref exception, Array.Empty<object>());
				ReportException(exception, null);
				return new List<MethodInfo>();
			}
			List<MethodInfo> result = new List<MethodInfo>();
			MethodBase lastOriginal = null;
			try
			{
				List<MethodBase> bulkMethods = GetBulkMethods();
				if (bulkMethods.Count == 1)
				{
					lastOriginal = bulkMethods[0];
				}
				ReversePatch(ref lastOriginal);
				result = ((bulkMethods.Count > 0) ? BulkPatch(bulkMethods, ref lastOriginal) : PatchWithAttributes(ref lastOriginal));
			}
			catch (Exception ex)
			{
				exception = ex;
			}
			RunMethod<HarmonyCleanup>(ref exception, new object[1] { exception });
			ReportException(exception, lastOriginal);
			return result;
		}

		private void ReversePatch(ref MethodBase lastOriginal)
		{
			for (int i = 0; i < patchMethods.Count; i++)
			{
				AttributePatch attributePatch = patchMethods[i];
				if (attributePatch.type == HarmonyPatchType.ReversePatch)
				{
					MethodBase originalMethod = attributePatch.info.GetOriginalMethod();
					if ((object)originalMethod != null)
					{
						lastOriginal = originalMethod;
					}
					ReversePatcher reversePatcher = instance.CreateReversePatcher(lastOriginal, attributePatch.info);
					lock (PatchProcessor.locker)
					{
						reversePatcher.Patch();
					}
				}
			}
		}

		private List<MethodInfo> BulkPatch(List<MethodBase> originals, ref MethodBase lastOriginal)
		{
			PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>();
			for (int i = 0; i < originals.Count; i++)
			{
				lastOriginal = originals[i];
				PatchJobs<MethodInfo>.Job job = patchJobs.GetJob(lastOriginal);
				foreach (AttributePatch patchMethod in patchMethods)
				{
					string text = "You cannot combine TargetMethod, TargetMethods or [HarmonyPatchAll] with individual annotations";
					HarmonyMethod info = patchMethod.info;
					if (info.methodName != null)
					{
						throw new ArgumentException(text + " [" + info.methodName + "]");
					}
					if (info.methodType.HasValue && info.methodType.Value != 0)
					{
						throw new ArgumentException($"{text} [{info.methodType}]");
					}
					if (info.argumentTypes != null)
					{
						throw new ArgumentException(text + " [" + info.argumentTypes.Description() + "]");
					}
					job.AddPatch(patchMethod);
				}
			}
			foreach (PatchJobs<MethodInfo>.Job job2 in patchJobs.GetJobs())
			{
				lastOriginal = job2.original;
				ProcessPatchJob(job2);
			}
			return patchJobs.GetReplacements();
		}

		private List<MethodInfo> PatchWithAttributes(ref MethodBase lastOriginal)
		{
			PatchJobs<MethodInfo> patchJobs = new PatchJobs<MethodInfo>();
			foreach (AttributePatch patchMethod in patchMethods)
			{
				lastOriginal = patchMethod.info.GetOriginalMethod();
				if ((object)lastOriginal == null)
				{
					throw new ArgumentException("Undefined targ

RealCity.dll

Decompiled 9 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Xml.Serialization;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Colossal.Logging;
using Game.Prefabs;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RealCity.Config;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RealCity")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Real City Services - rebalances city services.")]
[assembly: AssemblyFileVersion("0.2.0.0")]
[assembly: AssemblyInformationalVersion("0.2.0+f6b287d5b8cdcbfc90235fc8ae4f1da7d2281b95")]
[assembly: AssemblyProduct("RealCity")]
[assembly: AssemblyTitle("RealCity")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.0.0")]
[module: UnverifiableCode]
[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 RealCity
{
	[HarmonyPatch]
	internal class Patches
	{
	}
	[BepInPlugin("RealCity", "RealCity", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		private static ILog s_Log;

		public static ConfigEntry<bool> Logging;

		public static ConfigEntry<bool> ConfigDump;

		public static void LogIf(string text, bool bMethod = false)
		{
			if (Logging.Value)
			{
				Log(text, bMethod);
			}
		}

		public static void Log(string text, bool bMethod = false)
		{
			if (bMethod)
			{
				text = GetCallingMethod(2) + ": " + text;
			}
			Logger.LogInfo((object)text);
			s_Log.Info((object)text);
		}

		public static void LogStack(string text)
		{
			Logger.LogInfo((object)(text + " STACKTRACE"));
			s_Log.logStackTrace = true;
			s_Log.Info((object)(text + "STACKTRACE"));
			s_Log.logStackTrace = false;
		}

		public static string GetCallingMethod(int frame)
		{
			MethodBase method = new StackTrace().GetFrame(frame).GetMethod();
			return method.DeclaringType?.ToString() + "." + method.Name;
		}

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			s_Log = LogManager.GetLogger("RealCity");
			Logging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Logging", false, "Enables detailed logging.");
			ConfigDump = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ConfigDump", false, "Saves configuration to a secondary xml file.");
			Log("Plugin RealCity is loaded!");
			MethodBase[] array = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "RealCity_Cities2Harmony").GetPatchedMethods().ToArray();
			Log("Plugin RealCity made patches! Patched methods: " + array.Length);
			MethodBase[] array2 = array;
			foreach (MethodBase methodBase in array2)
			{
				Log("Patched method: " + methodBase.Module.Name + ":" + methodBase.Name);
			}
			ConfigToolXml.LoadConfig();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "RealCity";

		public const string PLUGIN_NAME = "RealCity";

		public const string PLUGIN_VERSION = "0.2.0";
	}
}
namespace RealCity.Config
{
	[HarmonyPatch]
	public static class ConfigTool_Patches
	{
		public static void DumpFields(PrefabBase prefab, ComponentBase component)
		{
			string name = ((object)component).GetType().Name;
			Plugin.Log(((Object)prefab).name + "." + ((Object)component).name + ".CLASS: " + name);
			FieldInfo[] fields = ((object)component).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (fieldInfo.Name != "isDirty" && fieldInfo.Name != "active" && fieldInfo.Name != "components")
				{
					object value = fieldInfo.GetValue(component);
					Plugin.Log($"{((Object)prefab).name}.{((Object)component).name}.{fieldInfo.Name}: {value}");
				}
			}
		}

		private static void ConfigureComponent(PrefabBase prefab, PrefabXml prefabConfig, ComponentBase component)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: 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)
			string name = ((object)component).GetType().Name;
			if (name == "ProcessingCompany" && prefabConfig.TryGetComponent("IndustrialProcess", out var component2))
			{
				ProcessingCompany val = (ProcessingCompany)(object)((component is ProcessingCompany) ? component : null);
				IndustrialProcess process = val.process;
				if (component2.TryGetField("m_MaxWorkersPerCell", out var field) && field.ValueFloatSpecified)
				{
					val.process.m_MaxWorkersPerCell = field.ValueFloat ?? process.m_MaxWorkersPerCell;
					Plugin.LogIf($"{((Object)prefab).name}.IndustrialProcess.{field.Name}: {process.m_MaxWorkersPerCell} -> {val.process.m_MaxWorkersPerCell} ({val.process.m_MaxWorkersPerCell.GetType()}, {field})");
				}
				if (component2.TryGetField("m_Output.m_Amount", out var field2) && field2.ValueIntSpecified)
				{
					val.process.m_Output.m_Amount = field2.ValueInt ?? process.m_Output.m_Amount;
					Plugin.LogIf($"{((Object)prefab).name}.IndustrialProcess.{field2.Name}: {process.m_Output.m_Amount} -> {val.process.m_Output.m_Amount} ({val.process.m_Output.m_Amount.GetType()}, {field2})");
				}
				if (!Plugin.Logging.Value)
				{
					Plugin.Log($"{((Object)prefab).name}.IndustrialProcess: wpc {val.process.m_MaxWorkersPerCell} output {val.process.m_Output.m_Amount}");
				}
			}
			if (!prefabConfig.TryGetComponent(name, out var component3))
			{
				Plugin.LogIf(((Object)prefab).name + "." + name + ": SKIP");
				return;
			}
			Plugin.LogIf(((Object)prefab).name + "." + name + ": valid");
			foreach (FieldXml field4 in component3.Fields)
			{
				FieldInfo field3 = ((object)component).GetType().GetField(field4.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field3 != null)
				{
					object value = field3.GetValue(component);
					if (field3.FieldType == typeof(float))
					{
						field3.SetValue(component, field4.ValueFloat);
					}
					else
					{
						field3.SetValue(component, field4.ValueInt);
					}
					if (Plugin.Logging.Value)
					{
						Plugin.Log($"{((Object)prefab).name}.{name}.{field3.Name}: {value} -> {field3.GetValue(component)} ({field3.FieldType}, {field4})");
					}
					else
					{
						Plugin.Log($"{((Object)prefab).name}.{name}.{field3.Name}: {field3.GetValue(component)}");
					}
				}
				else
				{
					Plugin.Log(((Object)prefab).name + "." + name + ": Warning! Field " + field4.Name + " not found in the component.");
				}
			}
			if (Plugin.Logging.Value)
			{
				DumpFields(prefab, component);
			}
		}

		private static void ConfigurePrefab(PrefabBase prefab, PrefabXml prefabConfig)
		{
			Plugin.LogIf(((Object)prefab).name + ": valid " + ((object)prefab).GetType().Name);
			ConfigureComponent(prefab, prefabConfig, (ComponentBase)(object)prefab);
			foreach (ComponentBase component in prefab.components)
			{
				ConfigureComponent(prefab, prefabConfig, component);
			}
		}

		[HarmonyPatch(typeof(PrefabSystem), "AddPrefab")]
		[HarmonyPrefix]
		public static bool PrefabSystem_AddPrefab_Prefix(object __instance, PrefabBase prefab)
		{
			if (ConfigToolXml.Config.IsPrefabValid(((object)prefab).GetType().Name))
			{
				if (ConfigToolXml.Config.TryGetPrefab(((Object)prefab).name, out var prefab2))
				{
					ConfigurePrefab(prefab, prefab2);
				}
				else
				{
					Plugin.LogIf(((Object)prefab).name + ": SKIP " + ((object)prefab).GetType().Name);
				}
			}
			return true;
		}

		[HarmonyPatch(typeof(PrefabInitializeSystem), "OnUpdate")]
		[HarmonyPostfix]
		public static void OnUpdate_Postfix()
		{
			if (Plugin.ConfigDump.Value)
			{
				ConfigToolXml.SaveConfig();
			}
		}
	}
	[XmlRoot("Configuration")]
	public class ConfigurationXml
	{
		[XmlArray("ValidPrefabTypes")]
		[XmlArrayItem(typeof(string), ElementName = "PrefabType")]
		public string[] ValidPrefabTypes;

		[XmlElement("Prefab")]
		public List<PrefabXml> Prefabs { get; set; }

		public bool IsPrefabValid(string nameToCheck)
		{
			if (ValidPrefabTypes == null || ValidPrefabTypes.Length == 0)
			{
				return false;
			}
			return Array.IndexOf(ValidPrefabTypes, nameToCheck) != -1;
		}

		public bool TryGetPrefab(string name, out PrefabXml prefab)
		{
			prefab = null;
			foreach (PrefabXml prefab2 in Prefabs)
			{
				if (prefab2.Name == name)
				{
					prefab = prefab2;
					return true;
				}
			}
			return false;
		}
	}
	public class PrefabXml
	{
		[XmlAttribute("name")]
		public string Name { get; set; }

		[XmlElement("Component")]
		public List<ComponentXml> Components { get; set; }

		public override string ToString()
		{
			return "PrefabXml: " + Name;
		}

		public void DumpToLog()
		{
			Plugin.Log(ToString());
			foreach (ComponentXml component in Components)
			{
				component.DumpToLog();
			}
		}

		internal bool TryGetComponent(string name, out ComponentXml component)
		{
			component = null;
			foreach (ComponentXml component2 in Components)
			{
				if (component2.Name == name)
				{
					component = component2;
					return true;
				}
			}
			return false;
		}
	}
	public class ComponentXml
	{
		[XmlAttribute("name")]
		public string Name { get; set; }

		[XmlElement("Field")]
		public List<FieldXml> Fields { get; set; }

		public override string ToString()
		{
			return "ComponentXml: " + Name;
		}

		public void DumpToLog()
		{
			Plugin.Log(ToString());
			foreach (FieldXml field in Fields)
			{
				Plugin.Log(field.ToString());
			}
		}

		internal bool TryGetField(string name, out FieldXml field)
		{
			field = null;
			foreach (FieldXml field2 in Fields)
			{
				if (field2.Name == name)
				{
					field = field2;
					return true;
				}
			}
			return false;
		}
	}
	public class FieldXml
	{
		[XmlAttribute("name")]
		public string Name { get; set; }

		[XmlAttribute(AttributeName = "value", DataType = "string")]
		public string Value { get; set; }

		[XmlIgnore]
		public bool ValueIntSpecified { get; set; }

		[XmlIgnore]
		public int? ValueInt { get; set; }

		[XmlAttribute("valueInt")]
		public int XmlValueInt
		{
			get
			{
				return ValueInt.GetValueOrDefault();
			}
			set
			{
				ValueInt = value;
				ValueIntSpecified = true;
			}
		}

		[XmlIgnore]
		public bool ValueFloatSpecified { get; set; }

		[XmlIgnore]
		public float? ValueFloat { get; set; }

		[XmlAttribute(AttributeName = "valueFloat", DataType = "float")]
		public float XmlValueFloat
		{
			get
			{
				return ValueFloat.GetValueOrDefault();
			}
			set
			{
				ValueFloat = value;
				ValueFloatSpecified = true;
			}
		}

		public override string ToString()
		{
			string text = Name + "=";
			if (ValueInt.HasValue)
			{
				text += $" {ValueInt} (int)";
			}
			if (ValueFloat.HasValue)
			{
				text += $" {ValueFloat} (float)";
			}
			if (!string.IsNullOrEmpty(Value))
			{
				text = text + " " + Value;
			}
			return text;
		}
	}
	public static class ConfigToolXml
	{
		private static readonly string _configFileName = "Config.xml";

		private static readonly string _assemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

		private static readonly string _configFile = Path.Combine(_assemblyPath, _configFileName);

		private static readonly string _dumpFileName = "Config_Dump.xml";

		private static readonly string _dumpFile = Path.Combine(_assemblyPath, _dumpFileName);

		private static ConfigurationXml _config = null;

		public static ConfigurationXml Config => _config;

		public static void LoadConfig()
		{
			try
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigurationXml));
				using (FileStream stream = new FileStream(_configFile, FileMode.Open))
				{
					_config = (ConfigurationXml)xmlSerializer.Deserialize(stream);
				}
				if (Config.ValidPrefabTypes.Length == 0)
				{
					Plugin.Log("Warning! No valid prefab types are defined.");
				}
				else
				{
					Plugin.LogIf($"VALID PREFAB TYPES {Config.ValidPrefabTypes.Length}");
					string[] validPrefabTypes = Config.ValidPrefabTypes;
					for (int i = 0; i < validPrefabTypes.Length; i++)
					{
						Plugin.LogIf(validPrefabTypes[i]);
					}
				}
				if (!Plugin.Logging.Value)
				{
					return;
				}
				Plugin.Log("PREFAB CONFIG DATA");
				foreach (PrefabXml item in Config?.Prefabs)
				{
					item.DumpToLog();
				}
			}
			catch (Exception ex)
			{
				Plugin.Log("ERROR: Cannot load settings, exception " + ex.Message);
				_config = null;
			}
		}

		public static void SaveConfig()
		{
			try
			{
				XmlSerializer xmlSerializer = new XmlSerializer(typeof(ConfigurationXml));
				using (FileStream stream = new FileStream(_dumpFile, FileMode.Create))
				{
					xmlSerializer.Serialize(stream, Config);
				}
				Plugin.Log("Configuration saved to file " + _dumpFile + ".");
			}
			catch (Exception ex)
			{
				Plugin.Log("ERROR: Cannot save configuration, exception " + ex.Message + ".");
			}
		}
	}
}