Decompiled source of LC Simplified Chinese Localization v2.5.0

BepInEx/core/XUnity.Common.dll

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

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

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

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

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

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

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

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

			public bool DirectBoxValueAccess { get; }

			public bool ForceNonVirtCall { get; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private static readonly WeakDictionary<object, object> WeakDynamicFields;

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

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

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

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

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

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

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

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

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

		private static readonly MethodInfo PatchMethod20;

		private static readonly object Harmony;

		private static bool _loggedHarmonyError;

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

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

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

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

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

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

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

		public const int VeryLow = 100;

		public const int Low = 200;

		public const int LowerThanNormal = 300;

		public const int Normal = 400;

		public const int HigherThanNormal = 500;

		public const int High = 600;

		public const int VeryHigh = 700;

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

			public int Filter { get; }

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

		private static readonly object Sync = new object();

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

		private static bool _initialized;

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

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

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

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

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

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

			public string MemberName { get; set; }

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

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

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

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

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

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

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

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

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

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

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

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

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

		private FastReflectionDelegate _invoke;

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

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

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

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

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

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

		private FastReflectionDelegate _set;

		private FastReflectionDelegate _get;

		public Type PropertyType { get; }

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

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

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

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

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

		private Action<object, object> _set;

		public Type FieldType { get; }

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

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

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

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

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

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

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

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

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

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

		public override bool IsAlive => true;

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

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

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

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

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

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

		private WeakKeyComparer<TKey> comparer;

		public override int Count => dictionary.Count;

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

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

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

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

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

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

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

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

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

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

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

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

			public int Count => dictionary.Count;

			public bool IsReadOnly => true;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private KeyCollection keys;

		private ValueCollection values;

		public abstract int Count { get; }

		public bool IsReadOnly => false;

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

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

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

		public abstract void Clear();

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

		public abstract bool ContainsKey(TKey key);

		public abstract bool Remove(TKey key);

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

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

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

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

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

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

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

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

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

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

			public const int Fatal = 1;

			public const int Error = 2;

			public const int Warning = 4;

			public const int Message = 8;

			public const int Info = 16;

			public const int Debug = 32;

			public const int All = 63;
		}

		private static Action<LogLevel, string> _logMethod;

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

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

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

		private static XuaLogger _common;

		private static XuaLogger _resourceRedirector;

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

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

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

		public string Source { get; set; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public Type UnityType { get; }

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

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

		public static bool SupportsMouseScrollDelta { get; }

		public static bool SupportsClipboard { get; }

		public static bool SupportsCustomYieldInstruction { get; }

		public static bool SupportsSceneManager { get; }

		public static bool SupportsWaitForSecondsRealtime { get; set; }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		public static class GameObject_Methods
		{
		}

		public static class TextMesh_Methods
		{
		}

		public static class Text_Methods
		{
		}

		public static class InputField_Methods
		{
		}

		public static class TMP_Text_Methods
		{
		}

		public static class TMP_InputField_Methods
		{
		}

		public static class TextMeshPro_Methods
		{
		}

		public static class TextMeshProUGUI_Methods
		{
		}

		public static class UILabel_Methods
		{
		}

		public static class UIRect_Methods
		{
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

BepInEx/plugins/AHook.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using AHook.Patches;
using AHook.Patches.util;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using XUnity.Common.Extensions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("GameTranslator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GameTranslator")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("acc996e2-652f-4af2-ab3b-8062a6acc7e4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AHook
{
	[BepInPlugin("AHook", "AHook", "1.0.0")]
	public class AHookPlugin : BaseUnityPlugin
	{
		private const string PLUGIN_GUID = "AHook";

		private const string PLUGIN_NAME = "AHook";

		private const string PLUGIN_VERSION = "1.0.0";

		internal static AHookPlugin Instance;

		private readonly Harmony harmony = new Harmony("AHook");

		public static string ConfigPath;

		public static string DefaultPath;

		public static string TexturesPath;

		public static bool shouldTranslate;

		public static ManualLogSource logger;

		private void Awake()
		{
			logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"插件AHook已加载!");
			ConfigPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("AHook.cfg", "");
			DefaultPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("AHook.cfg", "translations\\zh-CN\\");
			TranslateConfig.Load();
			ModHook.PatchAll(harmony);
		}

		public static void LogInfo(string info)
		{
			if (logger != null)
			{
				logger.LogInfo((object)info);
			}
		}
	}
	public class TranslateConfig
	{
		public class TranslateConfigFile
		{
			public string ConfigFilePath;

			public string ConfigFileName;

			public bool shouldTranslate = false;

			public int shouldTranslateMinLength = 200;

			public int shouldTranslateMaxLength = 0;

			public bool shouldLoad = true;

			public IDictionary<string, string> normal = new Dictionary<string, string>();

			public IDictionary<string, string> strong = new Dictionary<string, string>();

			public IDictionary<string, string> special = new Dictionary<string, string>();

			public IDictionary<string, string> useRex = new Dictionary<string, string>();

			public static HashSet<TranslateConfigFile> configs = new HashSet<TranslateConfigFile>();

			public Dictionary<string, string> translatePairs = new Dictionary<string, string>();

			public bool isOrgin = false;

			public static Regex regex = new Regex("(?<!\\\\)=");

			private List<string> logs = new List<string>();

			public TranslateConfigFile(string configName, bool saveOnInit, bool shouldLoad, bool origin = false)
			{
				ConfigFileName = configName;
				isOrgin = origin;
				if (origin)
				{
					ConfigFilePath = AHookPlugin.ConfigPath + configName + ".cfg";
				}
				else
				{
					ConfigFilePath = AHookPlugin.DefaultPath + configName + ".cfg";
				}
				this.shouldLoad = shouldLoad;
				if (ConfigFilePath == null)
				{
					throw new ArgumentNullException("configPath");
				}
				ConfigFilePath = Path.GetFullPath(ConfigFilePath);
				if (this.shouldLoad && File.Exists(ConfigFilePath))
				{
					Reload();
				}
				else if (saveOnInit)
				{
					Save();
				}
				configs.Add(this);
			}

			public void show()
			{
				foreach (KeyValuePair<string, string> item in normal)
				{
					string text = item.Key.Replace("=", "\\=");
					string text2 = item.Value.Replace("=", "\\=");
					AHookPlugin.LogInfo(text + "=" + text2);
				}
			}

			public void Reload()
			{
				normal.Clear();
				useRex.Clear();
				string[] array = File.ReadAllLines(ConfigFilePath);
				foreach (string text in array)
				{
					if (text.StartsWith("#") || !text.Contains("="))
					{
						continue;
					}
					string[] array2 = regex.Split(text);
					if (array2.Length != 2)
					{
						continue;
					}
					string text2 = array2[0].Replace("\\=", "=");
					string text3 = array2[1].Replace("\\=", "=");
					if (isOrgin)
					{
						text2 = text2.Trim();
						text3 = text3.Trim();
					}
					if (text2.StartsWith(rexName))
					{
						text2 = text2.Replace(rexName, "");
						if (useRex.ContainsKey(text2))
						{
							useRex[text2] = text3;
						}
						else
						{
							useRex.Add(text2, text3);
						}
					}
					else if (text2.StartsWith(strongName))
					{
						text2 = text2.Replace(strongName, "");
						if (strong.ContainsKey(text2))
						{
							strong[text2] = text3;
						}
						else
						{
							strong.Add(text2, text3);
						}
					}
					else if (normal.ContainsKey(text2))
					{
						normal[text2] = text3;
						special[text3] = text2;
					}
					else
					{
						normal.Add(text2, text3);
						if (!special.ContainsKey(text3))
						{
							special.Add(text3, text2);
						}
					}
					if (text2.Length < shouldTranslateMinLength)
					{
						shouldTranslateMinLength = text2.Length;
					}
					if (text2.Length > shouldTranslateMaxLength)
					{
						shouldTranslateMaxLength = text2.Length;
					}
				}
			}

			public void Log(string text)
			{
				logs.Add(text);
				string directoryName = Path.GetDirectoryName(ConfigFilePath);
				if (directoryName == null)
				{
					Directory.CreateDirectory(directoryName);
				}
				List<string> list = new List<string>();
				list.Add("##" + ConfigFileName);
				File.WriteAllLines(ConfigFilePath, logs);
			}

			public void Save()
			{
				string directoryName = Path.GetDirectoryName(ConfigFilePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				if (!File.Exists(ConfigFilePath))
				{
					File.Create(ConfigFilePath).Close();
				}
				else
				{
					if (!shouldLoad)
					{
						return;
					}
					List<string> list = new List<string>();
					list.Add("##" + ConfigFileName);
					foreach (KeyValuePair<string, string> item in normal)
					{
						string text = item.Key.Replace("=", "\\=");
						string text2 = item.Value.Replace("=", "\\=");
						list.Add(text + "=" + text2);
					}
					list.Add("##强制替换");
					foreach (KeyValuePair<string, string> item2 in strong)
					{
						string text3 = item2.Key.Replace("=", "\\=");
						string text4 = item2.Value.Replace("=", "\\=");
						list.Add(strongName + text3 + "=" + text4);
					}
					list.Add("##正则表达式");
					foreach (KeyValuePair<string, string> item3 in useRex)
					{
						string text5 = item3.Key.Replace("=", "\\=");
						string text6 = item3.Value.Replace("=", "\\=");
						list.Add(rexName + text5 + "=" + text6);
					}
					File.WriteAllLines(ConfigFilePath, list.ToArray());
				}
			}
		}

		public static TranslateConfigFile mod;

		public static TranslateConfigFile items;

		public static string rexName = "rex:";

		public static string strongName = "stg:";

		public static void Load()
		{
			items = CreateNewConfig("Item-Translate");
			mod = CreateConfig("GameTranslator");
		}

		private static TranslateConfigFile CreateConfig(string fileName)
		{
			return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true, origin: true);
		}

		private static TranslateConfigFile CreateNewConfig(string fileName, bool should)
		{
			return new TranslateConfigFile(fileName, saveOnInit: true, should);
		}

		private static TranslateConfigFile CreateNewConfig(string fileName)
		{
			AHookPlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
			return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true);
		}

		public static string getRegex(string pattern)
		{
			StringBuilder stringBuilder = new StringBuilder(pattern);
			stringBuilder.Replace("\\", "\\\\");
			return stringBuilder.ToString();
		}

		public static bool IsStringContainsEnglish(string input)
		{
			Regex regex = new Regex("[a-zA-Z]");
			return regex.IsMatch(input);
		}

		public static bool IsStringContainsChinese(string input)
		{
			Regex regex = new Regex("[\\u4e00-\\u9fa5]");
			return regex.IsMatch(input);
		}

		public static string useRegularExpression(string raw, string pattern, string result)
		{
			pattern = pattern.Replace(rexName, "");
			return Regex.Replace(raw, pattern, result);
		}

		public static string replaceByMap(string text, TranslateConfigFile file)
		{
			if (file.translatePairs.ContainsKey(text))
			{
				return file.translatePairs[text];
			}
			StringBuffer stringBuffer = new StringBuffer(text);
			foreach (KeyValuePair<string, string> item in file.useRex)
			{
				string pattern = Regex.Unescape(getRegex(item.Key));
				string result = Regex.Unescape(item.Value);
				string str = useRegularExpression(stringBuffer.ToString(), pattern, result);
				stringBuffer.Clear().Append(str);
			}
			foreach (KeyValuePair<string, string> item2 in file.strong)
			{
				string oldValue = Regex.Unescape(item2.Key);
				string newValue = Regex.Unescape(item2.Value);
				stringBuffer.Replace(oldValue, newValue);
			}
			foreach (KeyValuePair<string, string> item3 in file.normal)
			{
				string oldValue2 = Regex.Unescape(item3.Key);
				string newValue2 = Regex.Unescape(item3.Value);
				stringBuffer.ReplaceFull(oldValue2, newValue2);
			}
			file.translatePairs[text] = stringBuffer.ToString();
			return stringBuffer.ToString();
		}
	}
}
namespace AHook.Patches
{
	internal static class ModHook
	{
		internal class ReservedItemInfoHook
		{
			public static void Init(Harmony harmony)
			{
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a8: Expected O, but got Unknown
				Type type = Type.GetType("ReservedItemSlotCore.ReservedItemInfo, ReservedItemSlotCore");
				if (!(type == null))
				{
					AHookPlugin.LogInfo("Trying to be compatible with ReservedItemSlotCore");
					ConstructorInfo constructor = type.GetConstructor(new Type[6]
					{
						typeof(string),
						typeof(int),
						typeof(bool),
						typeof(bool),
						typeof(bool),
						typeof(bool)
					});
					MethodInfo method = typeof(ReservedItemInfoHook).GetMethod("Prefix");
					harmony.Patch((MethodBase)constructor, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}

			public static bool Prefix(ref string itemName, int hotbarSlotPriority, bool forceUpdateCanBeGrabbedBeforeGameStart, bool canBeGrabbedBeforeGameStart, bool forceUpdateRequiresBattery, bool requiresBattery)
			{
				try
				{
					if (itemName != null && !StringExtensions.IsNullOrWhiteSpace(itemName) && TranslateConfig.mod.normal.ContainsKey("Translate Items") && TranslateConfig.mod.normal["Translate Items"].Equals("true"))
					{
						itemName = TranslateConfig.replaceByMap(itemName, TranslateConfig.items);
					}
				}
				catch (Exception ex)
				{
					AHookPlugin.LogInfo("未找到GameTranslator模组:" + ex.Message);
				}
				return true;
			}
		}

		public static void PatchAll(Harmony harmony)
		{
			ReservedItemInfoHook.Init(harmony);
		}
	}
}
namespace AHook.Patches.util
{
	public class StringBuffer
	{
		private char[] value;

		private int length;

		private int capacity;

		private const int DEFAULT_CAPACITY = 16;

		public int Length
		{
			get
			{
				return length;
			}
			set
			{
				if (value < 0 || value > capacity)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				if (value < length)
				{
					Array.Clear(this.value, value, length - value);
				}
				length = value;
			}
		}

		public int Capacity
		{
			get
			{
				return capacity;
			}
			set
			{
				if (value < length)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				if (value != capacity)
				{
					char[] destinationArray = new char[value];
					Array.Copy(this.value, 0, destinationArray, 0, length);
					this.value = destinationArray;
					capacity = value;
				}
			}
		}

		public StringBuffer()
		{
			value = new char[16];
			length = 0;
			capacity = 16;
		}

		public StringBuffer(int capacity)
		{
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			value = new char[capacity];
			length = 0;
			this.capacity = capacity;
		}

		public StringBuffer(string str)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			value = new char[str.Length + 16];
			str.CopyTo(0, value, 0, str.Length);
			length = str.Length;
			capacity = str.Length + 16;
		}

		public void EnsureCapacity(int minimumCapacity)
		{
			if (minimumCapacity < 0)
			{
				throw new ArgumentOutOfRangeException("minimumCapacity");
			}
			if (minimumCapacity > capacity)
			{
				int num = capacity * 2;
				if (num < minimumCapacity)
				{
					num = minimumCapacity;
				}
				Capacity = num;
			}
		}

		public StringBuffer Append(object obj)
		{
			if (obj == null)
			{
				return this;
			}
			return Append(obj.ToString());
		}

		public StringBuffer Append(string str)
		{
			if (str == null)
			{
				return this;
			}
			int num = str.Length;
			EnsureCapacity(length + num);
			str.CopyTo(0, value, length, num);
			length += num;
			return this;
		}

		public StringBuffer Append(char c)
		{
			EnsureCapacity(length + 1);
			value[length] = c;
			length++;
			return this;
		}

		public StringBuffer Insert(int index, object obj)
		{
			if (obj == null)
			{
				return this;
			}
			return Insert(index, obj.ToString());
		}

		public StringBuffer Insert(int index, string str)
		{
			if (index < 0 || index > length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (str == null)
			{
				return this;
			}
			int num = str.Length;
			EnsureCapacity(length + num);
			Array.Copy(value, index, value, index + num, length - index);
			str.CopyTo(0, value, index, num);
			length += num;
			return this;
		}

		public StringBuffer Insert(int index, char c)
		{
			if (index < 0 || index > length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			EnsureCapacity(length + 1);
			Array.Copy(value, index, value, index + 1, length - index);
			value[index] = c;
			length++;
			return this;
		}

		public StringBuffer Remove(int startIndex, int length)
		{
			if (startIndex < 0 || startIndex > this.length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || startIndex + length > this.length)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			Array.Copy(value, startIndex + length, value, startIndex, this.length - startIndex - length);
			Array.Clear(value, this.length - length, length);
			this.length -= length;
			return this;
		}

		public StringBuffer Replace(char oldChar, char newChar)
		{
			for (int i = 0; i < length; i++)
			{
				if (value[i] == oldChar)
				{
					value[i] = newChar;
				}
			}
			return this;
		}

		public StringBuffer Replace(string oldValue, string newValue)
		{
			if (oldValue == null)
			{
				throw new ArgumentNullException("oldValue");
			}
			if (oldValue.Length == 0)
			{
				throw new ArgumentException("oldValue cannot be empty");
			}
			if (newValue == null)
			{
				newValue = string.Empty;
			}
			int num = oldValue.Length;
			int num2 = newValue.Length;
			for (int num3 = IndexOf(oldValue); num3 >= 0; num3 = IndexOf(oldValue, num3 + num2))
			{
				Remove(num3, num);
				Insert(num3, newValue);
			}
			return this;
		}

		public int IndexOf(char c)
		{
			return IndexOf(c, 0, length);
		}

		public int IndexOf(char c, int startIndex)
		{
			return IndexOf(c, startIndex, length - startIndex);
		}

		public int IndexOf(char c, int startIndex, int count)
		{
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return Array.IndexOf(value, c, startIndex, count);
		}

		public int IndexOf(string str)
		{
			return IndexOf(str, 0, length);
		}

		public int IndexOf(string str, int startIndex)
		{
			return IndexOf(str, startIndex, length - startIndex);
		}

		public int IndexOf(string str, int startIndex, int count)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return ToString(value, startIndex, count).IndexOf(str);
		}

		public static string ToString(char[] value, int startIndex, int count)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (startIndex < 0 || startIndex > value.Length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > value.Length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return new string(value, startIndex, count);
		}

		public string Substring(int startIndex)
		{
			return Substring(startIndex, length - startIndex);
		}

		public string Substring(int startIndex, int length)
		{
			if (startIndex < 0 || startIndex > this.length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || startIndex + length > this.length)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			return new string(value, startIndex, length);
		}

		public bool Contains(string text)
		{
			return IndexOf(text) >= 0;
		}

		public StringBuffer ReplaceFull(string oldValue, string newValue)
		{
			if (oldValue == null)
			{
				throw new ArgumentNullException("oldValue");
			}
			if (oldValue.Length == 0)
			{
				throw new ArgumentException("oldValue cannot be empty");
			}
			if (newValue == null)
			{
				newValue = string.Empty;
			}
			int num = oldValue.Length;
			int num2 = newValue.Length;
			for (int num3 = IndexOfWord(oldValue); num3 >= 0; num3 = IndexOfWord(oldValue, num3 + num2))
			{
				Remove(num3, num);
				Insert(num3, newValue);
			}
			return this;
		}

		private int IndexOfWord(string str)
		{
			return IndexOfWord(str, 0, length);
		}

		private int IndexOfWord(string str, int startIndex)
		{
			return IndexOfWord(str, startIndex, length - startIndex);
		}

		public int IndexOfWord(string str, int startIndex, int count)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			int num = str.Length;
			int[] array = new int[num];
			int num2 = 0;
			computeLPSArray(str, num, array);
			int num3 = startIndex;
			while (num3 < startIndex + count)
			{
				if (str[num2] == value[num3])
				{
					num2++;
					num3++;
				}
				if (num2 == num)
				{
					if ((num3 - num2 == 0 || !char.IsLetter(value[num3 - num2 - 1])) && (num3 == length || !char.IsLetter(value[num3])))
					{
						return num3 - num2;
					}
					num2 = array[num2 - 1];
				}
				else if (num3 < startIndex + count && str[num2] != value[num3])
				{
					if (num2 != 0)
					{
						num2 = array[num2 - 1];
					}
					else
					{
						num3++;
					}
				}
			}
			return -1;
		}

		private void computeLPSArray(string str, int M, int[] lps)
		{
			int num = 0;
			int num2 = 1;
			lps[0] = 0;
			while (num2 < M)
			{
				if (str[num2] == str[num])
				{
					num = (lps[num2] = num + 1);
					num2++;
				}
				else if (num != 0)
				{
					num = lps[num - 1];
				}
				else
				{
					lps[num2] = num;
					num2++;
				}
			}
		}

		private static bool IsWordChar(char c)
		{
			return char.IsLetter(c) || c == '_';
		}

		public StringBuffer Clear()
		{
			Length = 0;
			return this;
		}

		public override string ToString()
		{
			return new string(value, 0, length);
		}
	}
}

BepInEx/plugins/GameTranslator.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameTranslator.Patches.Hooks.texture;
using GameTranslator.Patches.Translatons;
using GameTranslator.Patches.Translatons.Manipulator;
using GameTranslator.Patches.Utils;
using HarmonyLib;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.UIElements;
using XUnity.Common.Constants;
using XUnity.Common.Extensions;
using XUnity.Common.Harmony;
using XUnity.Common.Logging;
using XUnity.Common.MonoMod;
using XUnity.Common.Utilities;

[assembly: AssemblyCompany("")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyProduct("GameTranslator")]
[assembly: AssemblyDescription("")]
[assembly: ComVisible(false)]
[assembly: Guid("acc996e2-652f-4af2-ab3b-8062a6acc7e4")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyTrademark("")]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyTitle("GameTranslator")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace GameTranslator
{
	public class TranslateConfig
	{
		public class TranslateConfigFile
		{
			public string ConfigFilePath;

			public string ConfigFileName;

			public bool shouldTranslate = false;

			public int shouldTranslateMinLength = 200;

			public int shouldTranslateMaxLength = 0;

			public bool shouldLoad = true;

			public IDictionary<string, string> normal = new Dictionary<string, string>();

			public IDictionary<string, string> strong = new Dictionary<string, string>();

			public IDictionary<string, string> special = new Dictionary<string, string>();

			public IDictionary<string, string> useRex = new Dictionary<string, string>();

			public static HashSet<TranslateConfigFile> configs = new HashSet<TranslateConfigFile>();

			public Dictionary<string, string> translatePairs = new Dictionary<string, string>();

			public static Regex regex = new Regex("(?<!\\\\)=");

			private List<string> logs = new List<string>();

			public TranslateConfigFile(string configName, bool saveOnInit, bool shouldLoad)
			{
				ConfigFileName = configName;
				ConfigFilePath = TranslatePlugin.DefaultPath + configName + ".xml";
				this.shouldLoad = shouldLoad;
				if (ConfigFilePath == null)
				{
					throw new ArgumentNullException("configPath");
				}
				ConfigFilePath = Path.GetFullPath(ConfigFilePath);
				if (this.shouldLoad && File.Exists(ConfigFilePath))
				{
					Reload();
				}
				else if (saveOnInit)
				{
					Save();
				}
				configs.Add(this);
			}

			public void Reload()
			{
				normal.Clear();
				useRex.Clear();
				string[] array = File.ReadAllLines(ConfigFilePath);
				foreach (string text in array)
				{
					if (text.StartsWith("#") || !text.Contains("="))
					{
						continue;
					}
					string[] array2 = regex.Split(text);
					if (array2.Length != 2)
					{
						continue;
					}
					string text2 = array2[0].Replace("\\=", "=");
					string text3 = array2[1].Replace("\\=", "=");
					if (text2.StartsWith(rexName))
					{
						text2 = text2.Replace(rexName, "");
						if (useRex.ContainsKey(text2))
						{
							useRex[text2] = text3;
						}
						else
						{
							useRex.Add(text2, text3);
						}
					}
					else if (text2.StartsWith(strongName))
					{
						text2 = text2.Replace(strongName, "");
						if (strong.ContainsKey(text2))
						{
							strong[text2] = text3;
						}
						else
						{
							strong.Add(text2, text3);
						}
					}
					else if (normal.ContainsKey(text2))
					{
						normal[text2] = text3;
						special[text3] = text2;
					}
					else
					{
						normal.Add(text2, text3);
						if (!special.ContainsKey(text3))
						{
							special.Add(text3, text2);
						}
					}
					if (text2.Length < shouldTranslateMinLength)
					{
						shouldTranslateMinLength = text2.Length;
					}
					if (text2.Length > shouldTranslateMaxLength)
					{
						shouldTranslateMaxLength = text2.Length;
					}
				}
			}

			public void Log(string text)
			{
				logs.Add(text);
				string directoryName = Path.GetDirectoryName(ConfigFilePath);
				if (directoryName == null)
				{
					Directory.CreateDirectory(directoryName);
				}
				List<string> list = new List<string>();
				list.Add("##" + ConfigFileName);
				File.WriteAllLines(ConfigFilePath, logs);
			}

			public void Save()
			{
				string directoryName = Path.GetDirectoryName(ConfigFilePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				if (!File.Exists(ConfigFilePath))
				{
					File.Create(ConfigFilePath).Close();
				}
				else
				{
					if (!shouldLoad)
					{
						return;
					}
					List<string> list = new List<string>();
					list.Add("##" + ConfigFileName);
					foreach (KeyValuePair<string, string> item in normal)
					{
						string text = item.Key.Replace("=", "\\=");
						string text2 = item.Value.Replace("=", "\\=");
						list.Add(text + "=" + text2);
					}
					list.Add("##强制替换");
					foreach (KeyValuePair<string, string> item2 in strong)
					{
						string text3 = item2.Key.Replace("=", "\\=");
						string text4 = item2.Value.Replace("=", "\\=");
						list.Add(strongName + text3 + "=" + text4);
					}
					list.Add("##正则表达式");
					foreach (KeyValuePair<string, string> item3 in useRex)
					{
						string text5 = item3.Key.Replace("=", "\\=");
						string text6 = item3.Value.Replace("=", "\\=");
						list.Add(rexName + text5 + "=" + text6);
					}
					File.WriteAllLines(ConfigFilePath, list.ToArray());
				}
			}
		}

		public static TranslateConfigFile normal;

		public static TranslateConfigFile hud;

		public static TranslateConfigFile items;

		public static TranslateConfigFile terminal;

		public static TranslateConfigFile text;

		public static TranslateConfigFile cmd_py;

		public static TranslateConfigFile cmd_zh;

		public static TranslateConfigFile log;

		public static TranslateConfigFile gui;

		public static TranslateConfigFile command;

		public static NormalTextTranslator normalText;

		public static NormalTextTranslator hudText;

		public static NormalTextTranslator guiText;

		public static TextureTranslationCache cache;

		public static string rexName = "rex:";

		public static string strongName = "stg:";

		public static void Load()
		{
			hud = CreateNewConfig("HUD-Translate", should: false);
			hud.shouldTranslate = TranslatePlugin.shouldTranslateHUD.Value;
			items = CreateNewConfig("Item-Translate");
			items.shouldTranslate = TranslatePlugin.shouldTranslateItems.Value;
			terminal = CreateNewConfig("Terminal-Translate");
			terminal.shouldTranslate = TranslatePlugin.shouldTranslateTerimal.Value;
			cmd_py = CreateNewConfig("CMD-PY-Translate");
			cmd_zh = CreateNewConfig("CMD-ZH-Translate");
			text = CreateNewConfig("SpecialText-Translate");
			text.shouldTranslate = TranslatePlugin.shouldTranslateSpecialText.Value;
			gui = CreateNewConfig("GuiText-Translate");
			gui.shouldTranslate = TranslatePlugin.shouldTranslateGui.Value;
			normal = CreateNewConfig("Normal-Translate", should: false);
			normal.shouldTranslate = TranslatePlugin.shouldTranslateNormalText.Value;
			normalText = new NormalTextTranslator(normal.ConfigFileName + ".xml");
			normalText.Load();
			hudText = new NormalTextTranslator(hud.ConfigFileName + ".xml");
			hudText.Load();
			cache = new TextureTranslationCache();
			cache.LoadTranslationFiles();
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher();
			string fullPath = Path.GetFullPath(TranslatePlugin.DefaultPath);
			TranslatePlugin.logger.LogInfo((object)("开始监测" + fullPath));
			fileSystemWatcher.Path = fullPath;
			fileSystemWatcher.Filter = "*.xml";
			fileSystemWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
			fileSystemWatcher.Changed += OnFileChange;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private static void OnFileChange(object sender, FileSystemEventArgs e)
		{
			if (e.ChangeType != WatcherChangeTypes.Created && e.ChangeType != WatcherChangeTypes.Changed)
			{
				return;
			}
			foreach (TranslateConfigFile config in TranslateConfigFile.configs)
			{
				if (config.shouldLoad && config.ConfigFilePath.ToLower().Contains(e.FullPath.ToLower()))
				{
					config.Reload();
					TextTranslate.ChangeTime++;
				}
			}
		}

		public static void show(TranslateConfigFile file)
		{
			foreach (string key in file.normal.Keys)
			{
				TranslatePlugin.LogInfo(key + "=" + file.normal[key]);
			}
		}

		private static TranslateConfigFile CreateNewConfig(string fileName, bool should)
		{
			TranslatePlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
			return new TranslateConfigFile(fileName, saveOnInit: true, should);
		}

		private static TranslateConfigFile CreateNewConfig(string fileName)
		{
			TranslatePlugin.logger.LogInfo((object)("GameTranslator正在载入配置文件" + fileName));
			return new TranslateConfigFile(fileName, saveOnInit: true, shouldLoad: true);
		}

		public static string getRegex(string pattern)
		{
			StringBuilder stringBuilder = new StringBuilder(pattern);
			stringBuilder.Replace("\\", "\\\\");
			return stringBuilder.ToString();
		}

		public static bool IsStringContainsEnglish(string input)
		{
			Regex regex = new Regex("[a-zA-Z]");
			return regex.IsMatch(input);
		}

		public static bool IsStringContainsChinese(string input)
		{
			Regex regex = new Regex("[\\u4e00-\\u9fa5]");
			return regex.IsMatch(input);
		}

		public static string useRegularExpression(string raw, string pattern, string result)
		{
			pattern = pattern.Replace(rexName, "");
			return Regex.Replace(raw, pattern, result);
		}

		public static string replaceByMap(string text, TranslateConfigFile file)
		{
			if (!file.shouldTranslate)
			{
				return text;
			}
			if (file.translatePairs.ContainsKey(text))
			{
				return file.translatePairs[text];
			}
			StringBuffer stringBuffer = new StringBuffer(text);
			foreach (KeyValuePair<string, string> item in file.useRex)
			{
				string pattern = Regex.Unescape(getRegex(item.Key));
				string result = Regex.Unescape(item.Value);
				string str = useRegularExpression(stringBuffer.ToString(), pattern, result);
				stringBuffer.Clear().Append(str);
			}
			foreach (KeyValuePair<string, string> item2 in file.strong)
			{
				string oldValue = Regex.Unescape(item2.Key);
				string newValue = Regex.Unescape(item2.Value);
				stringBuffer.Replace(oldValue, newValue);
			}
			foreach (KeyValuePair<string, string> item3 in file.normal)
			{
				string oldValue2 = Regex.Unescape(item3.Key);
				string newValue2 = Regex.Unescape(item3.Value);
				stringBuffer.ReplaceFull(oldValue2, newValue2);
			}
			file.translatePairs[text] = stringBuffer.ToString();
			return stringBuffer.ToString();
		}

		public static void Log(string text)
		{
			log.Log(text);
		}
	}
	[BepInPlugin("GameTranslator", "GameTranslator", "1.8.33")]
	public class TranslatePlugin : BaseUnityPlugin
	{
		public static ManualLogSource logger;

		public static ConfigEntry<string> language;

		public static ConfigEntry<bool> shouldHideModList;

		public static ConfigEntry<bool> shouldFixTipErrors;

		public static ConfigEntry<bool> shouldTranslateTerimal;

		public static ConfigEntry<bool> shouldTranslateNormalText;

		public static ConfigEntry<bool> shouldTranslateSpecialText;

		public static ConfigEntry<bool> shouldTranslateItems;

		public static ConfigEntry<bool> shouldTranslateHUD;

		public static ConfigEntry<bool> shouldTranslateGui;

		public static ConfigEntry<bool> TerimalCanUseChinese;

		public static ConfigEntry<bool> TerimalCanUsePinyinAbbreviation;

		public static ConfigEntry<bool> generateTerimalCommand;

		public static ConfigEntry<bool> changeFont;

		public static ConfigEntry<bool> changeTexture;

		public static ConfigEntry<string> overrideFont;

		public static ConfigEntry<string> alternateFontTextMeshPro;

		public static ConfigEntry<string> overrideFontTextMeshPro;

		public static ConfigEntry<string> shouldRemoveChar;

		private const string PLUGIN_GUID = "GameTranslator";

		private const string PLUGIN_NAME = "GameTranslator";

		private const string PLUGIN_VERSION = "1.8.33";

		internal static TranslatePlugin Instance;

		private readonly Harmony harmony = new Harmony("GameTranslator");

		public static string DefaultPath;

		public static string TexturesPath;

		public static bool shouldTranslate;

		private void Awake()
		{
			logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"插件GameTranslator已加载!");
			ConfigFile();
			HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.All, false);
			HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.Sprite, false);
			HookingHelper.PatchAll((IEnumerable<Type>)ImageHooks.SpriteRenderer, false);
			harmony.PatchAll();
		}

		private void ConfigFile()
		{
			language = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "Language", "zh-CN", "选择的语言,根据不同语言,目录位置不同");
			shouldHideModList = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Hide Mod List", true, "是否隐藏mod列表弹窗");
			shouldFixTipErrors = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Fix Tip Errors", true, "是否修复Tip提示界面乱码");
			shouldTranslateTerimal = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Terimal", true, "是否翻译终端");
			shouldTranslateGui = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Gui", true, "是否翻译Gui");
			shouldTranslateNormalText = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Normal Text", true, "是否翻译普通文本【需要整段字满足才替换】");
			shouldTranslateSpecialText = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Special Text", true, "是否翻译特殊文本【部分字满足就替换】");
			TerimalCanUseChinese = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Terimal Can Use Chinese", true, "终端是否可以用中文执行指令");
			TerimalCanUsePinyinAbbreviation = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Terimal Can Use Pinyin Abbreviation", true, "终端是否可以用拼音缩写执行指令");
			shouldTranslateItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate Items", true, "是否翻译物品");
			shouldTranslateHUD = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Translate HUD", true, "是否翻译聊天栏和小提示内容");
			changeFont = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Change Font", true, "是否更换字体(关闭后中文会乱码)");
			overrideFont = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "OverrideFont", "微软雅黑", "替换的字体");
			overrideFontTextMeshPro = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "OverrideFontTextMeshPro", "arialuni.cfg", "替换的字体文件");
			alternateFontTextMeshPro = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "AlternateFontTextMeshPro", "", "备用字体文件(如果出现口口的话,可以添加备用字体来解决)");
			shouldRemoveChar = ((BaseUnityPlugin)this).Config.Bind<string>("Setting", "shouldRemoveChars", "$0123456789*%", "需要移除的原版字体");
			changeTexture = ((BaseUnityPlugin)this).Config.Bind<bool>("Setting", "Change Texture", true, "是否更换图片");
			DefaultPath = ((BaseUnityPlugin)this).Config.ConfigFilePath.Replace("GameTranslator.cfg", "translations\\" + language.Value + "\\");
			TexturesPath = DefaultPath + "Texture\\";
			TranslateConfig.Load();
			TranslateExtensions.Load();
		}

		public static List<char> getShouldRemoveChars()
		{
			return shouldRemoveChar.Value.ToCharArray().ToList();
		}

		public static void LogInfo(string info)
		{
			if (logger != null)
			{
				logger.LogInfo((object)info);
			}
		}
	}
}
namespace GameTranslator.Patches.Translatons
{
	public class NormalTextTranslator
	{
		public Dictionary<string, string> _translations = new Dictionary<string, string>();

		public Dictionary<string, string> _strongTranslations = new Dictionary<string, string>();

		public Dictionary<string, string> _reverseTranslations = new Dictionary<string, string>();

		public Dictionary<string, string> _tokenTranslations = new Dictionary<string, string>();

		public Dictionary<string, string> _reverseTokenTranslations = new Dictionary<string, string>();

		private HashSet<string> _partialTranslations = new HashSet<string>();

		public List<RegexTranslation> _defaultRegexes = new List<RegexTranslation>();

		private HashSet<string> _registeredRegexes = new HashSet<string>();

		public List<RegexTranslationSplitter> _splitterRegexes = new List<RegexTranslationSplitter>();

		public HashSet<string> _registeredSplitterRegexes = new HashSet<string>();

		private FileSystemWatcher _fileWatcher;

		public string FileName;

		public string FilePath;

		public static Dictionary<string, NormalTextTranslator> keyValuePairs = new Dictionary<string, NormalTextTranslator>();

		public NormalTextTranslator(string fileName)
		{
			try
			{
				FileName = fileName;
				FilePath = TranslatePlugin.DefaultPath + fileName;
				_fileWatcher = new FileSystemWatcher();
				_fileWatcher.Path = Path.GetFullPath(TranslatePlugin.DefaultPath);
				_fileWatcher.Filter = FileName;
				_fileWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.LastAccess | NotifyFilters.CreationTime | NotifyFilters.Security;
				_fileWatcher.Changed += OnFileChange;
				_fileWatcher.IncludeSubdirectories = true;
				_fileWatcher.EnableRaisingEvents = true;
				_fileWatcher.Changed += OnFileChange;
				keyValuePairs.Add(FileName, this);
			}
			catch (Exception ex)
			{
				TranslatePlugin.logger.LogWarning((object)"在初始化翻译文件时发生错误!");
				TranslatePlugin.logger.LogError((object)ex);
			}
		}

		private static void OnFileChange(object sender, FileSystemEventArgs e)
		{
			if (e.ChangeType != WatcherChangeTypes.Created && e.ChangeType != WatcherChangeTypes.Changed)
			{
				return;
			}
			foreach (NormalTextTranslator value in keyValuePairs.Values)
			{
				if (value.FileName.StartsWith(e.Name))
				{
					value.Load();
				}
			}
			TextTranslate.ChangeTime++;
		}

		public void Load()
		{
			TranslatePlugin.logger.LogInfo((object)("--- 正在载入" + FileName + "文件 ---"));
			try
			{
				_defaultRegexes.Clear();
				_translations.Clear();
				_reverseTranslations.Clear();
				_partialTranslations.Clear();
				_tokenTranslations.Clear();
				_reverseTokenTranslations.Clear();
				_splitterRegexes.Clear();
				LoadTranslationsInStream(FilePath, FileName, isOutputFile: false, isLoad: true);
				if (!FileName.StartsWith("HUD-Translate"))
				{
					return;
				}
				foreach (string key in TranslateConfig.items.normal.Keys)
				{
					_strongTranslations[key] = TranslateConfig.items.normal[key];
				}
			}
			catch (Exception ex)
			{
				TranslatePlugin.logger.LogWarning((object)("在加载" + FileName + "文件时发生错误!"));
				TranslatePlugin.logger.LogError((object)ex);
			}
		}

		private void LoadTranslationsInStream(string stream, string fullFileName, bool isOutputFile, bool isLoad)
		{
			if (isLoad)
			{
				TranslatePlugin.logger.LogInfo((object)("正在加载文本文件: " + stream + "."));
			}
			StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
			string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text in array2)
			{
				try
				{
					string[] array3 = TextHelper.ReadTranslationLineAndDecode(text);
					if (array3 == null)
					{
						continue;
					}
					string text2 = array3[0];
					string value = array3[1];
					if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(value))
					{
						continue;
					}
					if (text2.StartsWith("sr:"))
					{
						try
						{
							RegexTranslationSplitter regex = new RegexTranslationSplitter(text2, value);
							AddTranslationSplitterRegex(regex);
						}
						catch (Exception ex)
						{
							TranslatePlugin.logger.LogWarning((object)("在构造正则表达式翻译分割器时发生错误: '" + text + "'." + Environment.NewLine + ex));
						}
					}
					else if (text2.StartsWith("r:"))
					{
						try
						{
							RegexTranslation regex2 = new RegexTranslation(text2, value);
							AddTranslationRegex(regex2);
						}
						catch (Exception ex2)
						{
							TranslatePlugin.logger.LogWarning((object)("在构造正则表达式转换时发生错误: '" + text + "'." + Environment.NewLine + ex2));
						}
					}
					else if (text2.StartsWith("sm:"))
					{
						try
						{
							text2 = text2.Substring(4, text2.Length - 5);
							AddStrongTranslation(text2, value);
						}
						catch (Exception ex3)
						{
							TranslatePlugin.logger.LogWarning((object)("在添加强匹配文本时发生错误: " + Environment.NewLine + ex3));
						}
					}
					else
					{
						AddTranslation(text2, value);
					}
				}
				catch (Exception ex4)
				{
					TranslatePlugin.logger.LogWarning((object)("在读取翻译时发生错误: '" + text + "'." + Environment.NewLine + ex4));
				}
			}
			streamReader.Close();
		}

		private void AddStrongTranslation(string key, string value)
		{
			if (key != null && value != null)
			{
				_strongTranslations[key] = value;
				_reverseTranslations[value] = key;
			}
		}

		private void AddTranslation(string key, string value)
		{
			if (key != null && value != null)
			{
				_translations[key] = value;
				_reverseTranslations[value] = key;
			}
		}

		private void AddTranslationSplitterRegex(RegexTranslationSplitter regex)
		{
			if (!_registeredSplitterRegexes.Contains(regex.Original))
			{
				_registeredSplitterRegexes.Add(regex.Original);
				_splitterRegexes.Add(regex);
			}
		}

		private void AddTranslationRegex(RegexTranslation regex)
		{
			if (!_registeredRegexes.Contains(regex.Original))
			{
				_registeredRegexes.Add(regex.Original);
				_defaultRegexes.Add(regex);
			}
		}

		private bool HasTranslated(string key)
		{
			return _translations.ContainsKey(key);
		}

		private bool IsTranslation(string translation)
		{
			if (_reverseTranslations.ContainsKey(translation))
			{
				return true;
			}
			return false;
		}

		private bool IsTokenTranslation(string translation)
		{
			return _reverseTokenTranslations.ContainsKey(translation);
		}

		public bool IsTranslatable(string text, bool isToken)
		{
			bool flag = !IsTranslation(text);
			if (isToken && flag)
			{
				flag = !IsTokenTranslation(text);
			}
			return flag;
		}

		private string ChangeRegex(string text)
		{
			Regex regex = new Regex("\\$([0-9]+)");
			return regex.Replace(text, ReplaceFunc);
			static string ReplaceFunc(Match match)
			{
				int num = int.Parse(match.Groups[1].Value);
				return "{" + (num - 1) + "}";
			}
		}

		public string SplitterTranslate(string text, RegexTranslationSplitter splitter, bool strong, bool ignoreCase)
		{
			StringBuilder stringBuilder = new StringBuilder(text);
			if (splitter.CompiledRegex != null)
			{
				MatchCollection matchCollection = splitter.CompiledRegex.Matches(text);
				foreach (Match item in matchCollection)
				{
					if (!item.Success)
					{
						continue;
					}
					List<string> list = new List<string>();
					string[] array = new string[item.Groups.Count];
					for (int i = 1; i < item.Groups.Count; i++)
					{
						string value = item.Groups[i].Value;
						StringBuffer stringBuffer = new StringBuffer(value);
						if (strong)
						{
							foreach (string key in _strongTranslations.Keys)
							{
								if (value.Contains(key))
								{
									stringBuffer.ReplaceFull(key, _strongTranslations[key]);
								}
							}
						}
						else
						{
							foreach (string key2 in _translations.Keys)
							{
								if (value.Contains(key2))
								{
									stringBuffer.ReplaceFull(key2, _translations[key2]);
								}
							}
						}
						array[i - 1] = stringBuffer.ToString();
					}
					string format = Regex.Unescape(getRegex(ChangeRegex(splitter.Translation)));
					object[] args = array;
					string newValue = string.Format(format, args);
					stringBuilder = stringBuilder.Replace(item.Value, newValue);
				}
			}
			return stringBuilder.ToString();
		}

		public static string getRegex(string pattern)
		{
			StringBuilder stringBuilder = new StringBuilder(pattern);
			stringBuilder.Replace("\\=", "\\\\=");
			return stringBuilder.ToString();
		}

		public string SplitterTranslate(string text, RegexTranslationSplitter splitter, bool strong)
		{
			return SplitterTranslate(text, splitter, strong, ignoreCase: false);
		}

		public string TryTranslateByStrong(string text)
		{
			string text2 = text;
			try
			{
				StringBuilder stringBuilder = new StringBuilder(text2);
				foreach (string key in _translations.Keys)
				{
					stringBuilder.Replace(key, _translations[key]);
				}
				text2 = stringBuilder.ToString();
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"弱匹配翻译出现问题.");
			}
			try
			{
				foreach (string key2 in _translations.Keys)
				{
					if (text2.Trim().Equals(key2.Trim()))
					{
						text2 = _translations[key2];
					}
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"强匹配出现问题.");
			}
			try
			{
				foreach (RegexTranslationSplitter splitterRegex in _splitterRegexes)
				{
					text2 = SplitterTranslate(text2, splitterRegex, strong: true, ignoreCase: true);
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"sr翻译出现问题.");
			}
			try
			{
				foreach (RegexTranslation defaultRegex in _defaultRegexes)
				{
					if (defaultRegex.CompiledRegex != null)
					{
						Match match = defaultRegex.CompiledRegex.Match(text2);
						if (match.Success)
						{
							text2 = defaultRegex.CompiledRegex.Replace(text2, defaultRegex.Translation);
						}
					}
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"r翻译出现问题.");
			}
			return text2;
		}

		public string TryTranslate(string text)
		{
			string text2 = text;
			try
			{
				foreach (string key in _translations.Keys)
				{
					if (text2.Trim().Equals(key.Trim()))
					{
						text2 = _translations[key];
					}
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"强匹配翻译出现问题.");
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder(text2);
				foreach (string key2 in _strongTranslations.Keys)
				{
					stringBuilder.Replace(key2, _strongTranslations[key2]);
				}
				text2 = stringBuilder.ToString();
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"弱匹配翻译出现问题.");
			}
			try
			{
				foreach (RegexTranslationSplitter splitterRegex in _splitterRegexes)
				{
					text2 = SplitterTranslate(text2, splitterRegex, strong: false);
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"sr翻译出现问题.");
			}
			try
			{
				foreach (RegexTranslation defaultRegex in _defaultRegexes)
				{
					if (defaultRegex.CompiledRegex != null)
					{
						Match match = defaultRegex.CompiledRegex.Match(text2);
						if (match.Success)
						{
							text2 = defaultRegex.CompiledRegex.Replace(text2, defaultRegex.Translation);
						}
					}
				}
			}
			catch (Exception)
			{
				TranslatePlugin.logger.LogInfo((object)"r翻译出现问题.");
			}
			return text2;
		}
	}
	public class TextureTranslationCache
	{
		internal class FileSystemTranslatedImageSource : TranslatedImage.ITranslatedImageSource
		{
			private readonly string _fileName;

			public FileSystemTranslatedImageSource(string fileName)
			{
				_fileName = fileName;
			}

			public byte[] GetData()
			{
				using FileStream fileStream = File.OpenRead(_fileName);
				return StreamExtensions.ReadFully((Stream)fileStream, 16384);
			}
		}

		internal static class HashHelper
		{
			private static readonly SHA1Managed SHA1 = new SHA1Managed();

			private static readonly uint[] Lookup32 = CreateLookup32();

			public static string Compute(byte[] data)
			{
				return ByteArrayToHexViaLookup32(SHA1.ComputeHash(data)).Substring(0, 10);
			}

			private static uint[] CreateLookup32()
			{
				uint[] array = new uint[256];
				for (int i = 0; i < 256; i++)
				{
					string text = i.ToString("X2");
					array[i] = text[0] + ((uint)text[1] << 16);
				}
				return array;
			}

			private static string ByteArrayToHexViaLookup32(byte[] bytes)
			{
				uint[] lookup = Lookup32;
				char[] array = new char[bytes.Length * 2];
				for (int i = 0; i < bytes.Length; i++)
				{
					uint num = lookup[bytes[i]];
					array[2 * i] = (char)num;
					array[2 * i + 1] = (char)(num >> 16);
				}
				return new string(array);
			}
		}

		public Dictionary<string, TranslatedImage> _translatedImages = new Dictionary<string, TranslatedImage>(StringComparer.InvariantCultureIgnoreCase);

		public HashSet<string> _untranslatedImages = new HashSet<string>();

		private Dictionary<string, string> _keyToFileName = new Dictionary<string, string>();

		private bool _disposed;

		public TextureTranslationCache()
		{
			try
			{
				Directory.CreateDirectory(TranslatePlugin.TexturesPath);
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing translation file watching for textures.");
			}
		}

		private void FileWatcher_DirectoryUpdated()
		{
		}

		private IEnumerable<string> GetTextureFiles()
		{
			return from x in Directory.GetFiles(TranslatePlugin.TexturesPath, "*.*", SearchOption.AllDirectories)
				where x.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || x.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)
				select x;
		}

		public void LoadTranslationFiles()
		{
			try
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				_translatedImages.Clear();
				_untranslatedImages.Clear();
				_keyToFileName.Clear();
				Directory.CreateDirectory(TranslatePlugin.TexturesPath);
				foreach (string textureFile in GetTextureFiles())
				{
					RegisterImageFromFile(textureFile);
				}
				float realtimeSinceStartup2 = Time.realtimeSinceStartup;
				XuaLogger.AutoTranslator.Debug($"Loaded texture files (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)");
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations.");
			}
		}

		private void RegisterImageFromStream(string fullFileName, TranslatedImage.ITranslatedImageSource source)
		{
			try
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullFileName);
				int num = fileNameWithoutExtension.LastIndexOf("[");
				int num2 = fileNameWithoutExtension.LastIndexOf("]");
				if (num2 > -1 && num > -1 && num2 > num)
				{
					int num3 = num + 1;
					string[] array = fileNameWithoutExtension.Substring(num3, num2 - num3).Split(new char[1] { '-' });
					string key;
					string x;
					if (array.Length == 1)
					{
						key = array[0];
						x = array[0];
					}
					else
					{
						if (array.Length != 2)
						{
							XuaLogger.AutoTranslator.Warn("Image not loaded (unknown hash): " + fullFileName + ".");
							return;
						}
						key = array[0];
						x = array[1];
					}
					byte[] data = source.GetData();
					string y = HashHelper.Compute(data);
					bool flag = StringComparer.InvariantCultureIgnoreCase.Compare(x, y) != 0;
					_keyToFileName[key] = fullFileName;
					if (flag)
					{
						RegisterTranslatedImage(fullFileName, key, data);
						XuaLogger.AutoTranslator.Debug("Image loaded: " + fullFileName + ".");
					}
					else
					{
						RegisterUntranslatedImage(key);
						XuaLogger.AutoTranslator.Warn("Image not loaded (unmodified): " + fullFileName + ".");
					}
				}
				else
				{
					XuaLogger.AutoTranslator.Warn("Image not loaded (no hash): " + fullFileName + ".");
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading texture file: " + fullFileName);
			}
		}

		private void RegisterImageFromFile(string fullFileName)
		{
			if (File.Exists(fullFileName))
			{
				FileSystemTranslatedImageSource source = new FileSystemTranslatedImageSource(fullFileName);
				RegisterImageFromStream(fullFileName, source);
			}
		}

		public void RenameFileWithKey(string name, string key, string newKey)
		{
			try
			{
				if (_keyToFileName.TryGetValue(key, out var value))
				{
					_keyToFileName.Remove(key);
					value.Replace(key, newKey);
					if (!IsImageRegistered(newKey))
					{
						byte[] data = File.ReadAllBytes(value);
						RegisterImageFromData(name, newKey, data);
						File.Delete(value);
						XuaLogger.AutoTranslator.Warn("Replaced old file with name '" + name + "' registered with key old '" + key + "'.");
					}
				}
			}
			catch (Exception ex)
			{
				XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to rename file with key '" + key + "'.");
			}
		}

		internal void RegisterImageFromData(string textureName, string key, byte[] data)
		{
			string text = StringExtensions.SanitizeForFileSystem(textureName);
			string text2 = HashHelper.Compute(data);
			string text3 = ((!(key == text2)) ? (text + " [" + key + "-" + text2 + "].png") : (text + " [" + key + "].png"));
			string text4 = Path.Combine(TranslatePlugin.TexturesPath, text3);
			File.WriteAllBytes(text4, data);
			XuaLogger.AutoTranslator.Info("Dumped texture file: " + text3);
			_keyToFileName[key] = text4;
			RegisterTranslatedImage(text4, key, data);
		}

		private void RegisterTranslatedImage(string fileName, string key, byte[] data)
		{
			_translatedImages[key] = new TranslatedImage(fileName, data, null);
		}

		private void RegisterUntranslatedImage(string key)
		{
			_untranslatedImages.Add(key);
		}

		internal bool IsImageRegistered(string key)
		{
			return _translatedImages.ContainsKey(key) || _untranslatedImages.Contains(key);
		}

		internal bool TryGetTranslatedImage(string key, out byte[] data, out TranslatedImage image)
		{
			if (_translatedImages.TryGetValue(key, out var value))
			{
				try
				{
					data = value.GetData();
					image = value;
					return data != null;
				}
				catch (Exception ex)
				{
					XuaLogger.AutoTranslator.Error(ex, "An error occurrd while attempting to load image: " + value.FileName);
					_translatedImages.Remove(key);
				}
			}
			data = null;
			image = null;
			return false;
		}

		private void Dispose(bool disposing)
		{
			if (!_disposed)
			{
				if (disposing)
				{
				}
				_disposed = true;
			}
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}
	}
}
namespace GameTranslator.Patches.Utils
{
	internal class TextTranslate
	{
		public static TextTranslate Instance = new TextTranslate();

		public static long ChangeTime = 0L;

		internal void Hook_TextChanged(object ui)
		{
			if (TerminalPatch.ig == null || !TerminalPatch.ig.Contains(ui))
			{
				TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo();
				bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo);
				if (TranslatePlugin.shouldTranslateSpecialText.Value || TranslatePlugin.shouldTranslateNormalText.Value)
				{
					TranslateImmediate(ui, null, orCreateTextTranslationInfo, TranslateConfig.normalText, TranslateConfig.text, ignoreComponentState);
				}
			}
		}

		internal void Hook_TextChanged(object ui, ref string value)
		{
			if (TerminalPatch.ig == null || !TerminalPatch.ig.Contains(ui))
			{
				TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo();
				bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo);
				if (TranslatePlugin.shouldTranslateSpecialText.Value || TranslatePlugin.shouldTranslateNormalText.Value)
				{
					value = TranslateImmediate(ui, value, orCreateTextTranslationInfo, TranslateConfig.normalText, TranslateConfig.text, ignoreComponentState);
				}
			}
		}

		public string TranslateImmediate(object ui, string text, TextTranslationInfo info, NormalTextTranslator normalText, TranslateConfig.TranslateConfigFile config, bool ignoreComponentState)
		{
			if (info != null && (info.IsCurrentlySettingText || info.MustIgnore))
			{
				return text;
			}
			text = text ?? ui.GetText(info);
			if (Utility.IsNullOrWhiteSpace(text))
			{
				return text;
			}
			if (info != null && info.IsTranslated)
			{
				if (!info.OriginalText.Equals(text) || info.ChangeTime != ChangeTime)
				{
					info.Reset(text);
				}
				else if (info.OriginalText.Equals(text) || info.TranslatedText.Equals(text))
				{
					return info.TranslatedText;
				}
			}
			string text2 = text;
			if ((normalText == null || normalText.IsTranslatable(text, isToken: false)) && (ignoreComponentState || ui.IsComponentActive()))
			{
				if (normalText != null && TranslatePlugin.shouldTranslateNormalText.Value)
				{
					text2 = normalText.TryTranslate(text2);
				}
				text2 = TranslateConfig.replaceByMap(text2, config);
				SetTranslatedText(ui, text2, text, info);
			}
			return text2;
		}

		internal void SetTranslatedText(object ui, string translatedText, string originalText, TextTranslationInfo info)
		{
			if (info != null)
			{
				info.OriginalText = originalText;
				info.SetTranslatedText(translatedText);
			}
			SetText(ui, translatedText, isTranslated: true, originalText, info);
		}

		private void SetText(object ui, string text, bool isTranslated, string originalText, TextTranslationInfo info)
		{
			if (info == null || !info.IsCurrentlySettingText)
			{
				if (info != null)
				{
					info.IsCurrentlySettingText = true;
				}
				ui.SetText(text, info);
				if (info != null)
				{
					info.IsCurrentlySettingText = false;
				}
			}
		}

		public bool DiscoverComponent(object ui, TextTranslationInfo info)
		{
			if (info == null || !TranslatePlugin.changeFont.Value)
			{
				return true;
			}
			try
			{
				bool flag = ui.IsComponentActive();
				if (TranslatePlugin.overrideFontTextMeshPro.Value != null && flag)
				{
					info.ChangeFont(ui);
					return true;
				}
				return flag;
			}
			catch (Exception ex)
			{
				TranslatePlugin.logger.LogWarning((object)("处理UI时发生错误." + Environment.NewLine + ex));
			}
			return false;
		}
	}
	public class StringBuffer
	{
		private char[] value;

		private int length;

		private int capacity;

		private const int DEFAULT_CAPACITY = 16;

		public int Length
		{
			get
			{
				return length;
			}
			set
			{
				if (value < 0 || value > capacity)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				if (value < length)
				{
					Array.Clear(this.value, value, length - value);
				}
				length = value;
			}
		}

		public int Capacity
		{
			get
			{
				return capacity;
			}
			set
			{
				if (value < length)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				if (value != capacity)
				{
					char[] destinationArray = new char[value];
					Array.Copy(this.value, 0, destinationArray, 0, length);
					this.value = destinationArray;
					capacity = value;
				}
			}
		}

		public StringBuffer()
		{
			value = new char[16];
			length = 0;
			capacity = 16;
		}

		public StringBuffer(int capacity)
		{
			if (capacity < 0)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			value = new char[capacity];
			length = 0;
			this.capacity = capacity;
		}

		public StringBuffer(string str)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			value = new char[str.Length + 16];
			str.CopyTo(0, value, 0, str.Length);
			length = str.Length;
			capacity = str.Length + 16;
		}

		public void EnsureCapacity(int minimumCapacity)
		{
			if (minimumCapacity < 0)
			{
				throw new ArgumentOutOfRangeException("minimumCapacity");
			}
			if (minimumCapacity > capacity)
			{
				int num = capacity * 2;
				if (num < minimumCapacity)
				{
					num = minimumCapacity;
				}
				Capacity = num;
			}
		}

		public StringBuffer Append(object obj)
		{
			if (obj == null)
			{
				return this;
			}
			return Append(obj.ToString());
		}

		public StringBuffer Append(string str)
		{
			if (str == null)
			{
				return this;
			}
			int num = str.Length;
			EnsureCapacity(length + num);
			str.CopyTo(0, value, length, num);
			length += num;
			return this;
		}

		public StringBuffer Append(char c)
		{
			EnsureCapacity(length + 1);
			value[length] = c;
			length++;
			return this;
		}

		public StringBuffer Insert(int index, object obj)
		{
			if (obj == null)
			{
				return this;
			}
			return Insert(index, obj.ToString());
		}

		public StringBuffer Insert(int index, string str)
		{
			if (index < 0 || index > length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			if (str == null)
			{
				return this;
			}
			int num = str.Length;
			EnsureCapacity(length + num);
			Array.Copy(value, index, value, index + num, length - index);
			str.CopyTo(0, value, index, num);
			length += num;
			return this;
		}

		public StringBuffer Insert(int index, char c)
		{
			if (index < 0 || index > length)
			{
				throw new ArgumentOutOfRangeException("index");
			}
			EnsureCapacity(length + 1);
			Array.Copy(value, index, value, index + 1, length - index);
			value[index] = c;
			length++;
			return this;
		}

		public StringBuffer Remove(int startIndex, int length)
		{
			if (startIndex < 0 || startIndex > this.length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || startIndex + length > this.length)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			Array.Copy(value, startIndex + length, value, startIndex, this.length - startIndex - length);
			Array.Clear(value, this.length - length, length);
			this.length -= length;
			return this;
		}

		public StringBuffer Replace(char oldChar, char newChar)
		{
			for (int i = 0; i < length; i++)
			{
				if (value[i] == oldChar)
				{
					value[i] = newChar;
				}
			}
			return this;
		}

		public StringBuffer Replace(string oldValue, string newValue)
		{
			if (oldValue == null)
			{
				throw new ArgumentNullException("oldValue");
			}
			if (oldValue.Length == 0)
			{
				throw new ArgumentException("oldValue cannot be empty");
			}
			if (newValue == null)
			{
				newValue = string.Empty;
			}
			int num = oldValue.Length;
			int num2 = newValue.Length;
			for (int num3 = IndexOf(oldValue); num3 >= 0; num3 = IndexOf(oldValue, num3 + num2))
			{
				Remove(num3, num);
				Insert(num3, newValue);
			}
			return this;
		}

		public int IndexOf(char c)
		{
			return IndexOf(c, 0, length);
		}

		public int IndexOf(char c, int startIndex)
		{
			return IndexOf(c, startIndex, length - startIndex);
		}

		public int IndexOf(char c, int startIndex, int count)
		{
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return Array.IndexOf(value, c, startIndex, count);
		}

		public int IndexOf(string str)
		{
			return IndexOf(str, 0, length);
		}

		public int IndexOf(string str, int startIndex)
		{
			return IndexOf(str, startIndex, length - startIndex);
		}

		public int IndexOf(string str, int startIndex, int count)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return value.ToString(startIndex, count).IndexOf(str);
		}

		public string Substring(int startIndex)
		{
			return Substring(startIndex, length - startIndex);
		}

		public string Substring(int startIndex, int length)
		{
			if (startIndex < 0 || startIndex > this.length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (length < 0 || startIndex + length > this.length)
			{
				throw new ArgumentOutOfRangeException("length");
			}
			return new string(value, startIndex, length);
		}

		public bool Contains(string text)
		{
			return IndexOf(text) >= 0;
		}

		public StringBuffer ReplaceFull(string oldValue, string newValue)
		{
			if (oldValue == null)
			{
				throw new ArgumentNullException("oldValue");
			}
			if (oldValue.Length == 0)
			{
				throw new ArgumentException("oldValue cannot be empty");
			}
			if (newValue == null)
			{
				newValue = string.Empty;
			}
			int num = oldValue.Length;
			int num2 = newValue.Length;
			for (int num3 = IndexOfWord(oldValue); num3 >= 0; num3 = IndexOfWord(oldValue, num3 + num2))
			{
				Remove(num3, num);
				Insert(num3, newValue);
			}
			return this;
		}

		private int IndexOfWord(string str)
		{
			return IndexOfWord(str, 0, length);
		}

		private int IndexOfWord(string str, int startIndex)
		{
			return IndexOfWord(str, startIndex, length - startIndex);
		}

		public int IndexOfWord(string str, int startIndex, int count)
		{
			if (str == null)
			{
				throw new ArgumentNullException("str");
			}
			if (startIndex < 0 || startIndex > length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			int num = str.Length;
			int[] array = new int[num];
			int num2 = 0;
			computeLPSArray(str, num, array);
			int num3 = startIndex;
			while (num3 < startIndex + count)
			{
				if (str[num2] == value[num3])
				{
					num2++;
					num3++;
				}
				if (num2 == num)
				{
					if ((num3 - num2 == 0 || !char.IsLetter(value[num3 - num2 - 1])) && (num3 == length || !char.IsLetter(value[num3])))
					{
						return num3 - num2;
					}
					num2 = array[num2 - 1];
				}
				else if (num3 < startIndex + count && str[num2] != value[num3])
				{
					if (num2 != 0)
					{
						num2 = array[num2 - 1];
					}
					else
					{
						num3++;
					}
				}
			}
			return -1;
		}

		private void computeLPSArray(string str, int M, int[] lps)
		{
			int num = 0;
			int num2 = 1;
			lps[0] = 0;
			while (num2 < M)
			{
				if (str[num2] == str[num])
				{
					num = (lps[num2] = num + 1);
					num2++;
				}
				else if (num != 0)
				{
					num = lps[num - 1];
				}
				else
				{
					lps[num2] = num;
					num2++;
				}
			}
		}

		private static bool IsWordChar(char c)
		{
			return char.IsLetter(c) || c == '_';
		}

		public StringBuffer Clear()
		{
			Length = 0;
			return this;
		}

		public override string ToString()
		{
			return new string(value, 0, length);
		}
	}
}
namespace GameTranslator.Patches.Hooks.texture
{
	internal static class ImageHooks
	{
		public static readonly Type[] All = new Type[20]
		{
			typeof(MaskableGraphic_OnEnable_Hook),
			typeof(Image_sprite_Hook),
			typeof(Image_overrideSprite_Hook),
			typeof(Image_material_Hook),
			typeof(RawImage_texture_Hook),
			typeof(Cursor_SetCursor_Hook),
			typeof(Material_mainTexture_Hook),
			typeof(CubismRenderer_MainTexture_Hook),
			typeof(CubismRenderer_TryInitialize_Hook),
			typeof(UIAtlas_spriteMaterial_Hook),
			typeof(UISprite_OnInit_Hook),
			typeof(UISprite_material_Hook),
			typeof(UISprite_atlas_Hook),
			typeof(UI2DSprite_sprite2D_Hook),
			typeof(UI2DSprite_material_Hook),
			typeof(UITexture_mainTexture_Hook),
			typeof(UITexture_material_Hook),
			typeof(UIPanel_clipTexture_Hook),
			typeof(UIRect_OnInit_Hook),
			typeof(DicingTextures_GetTexture_Hook)
		};

		public static readonly Type[] Sprite = new Type[1] { typeof(Sprite_texture_Hook) };

		public static readonly Type[] SpriteRenderer = new Type[1] { typeof(SpriteRenderer_sprite_Hook) };
	}
}
namespace GameTranslator.Patches.Translatons
{
	internal static class TranslateExtensions
	{
		public enum ImageFormat
		{
			PNG,
			TGA
		}

		private interface IPropertyMover
		{
			void MoveProperty(object source, object destination);
		}

		private class PropertyMover<T, TPropertyType> : IPropertyMover
		{
			private readonly Func<T, TPropertyType> _get;

			private readonly Action<T, TPropertyType> _set;

			public PropertyMover(PropertyInfo propertyInfo)
			{
				MethodInfo getMethod = propertyInfo.GetGetMethod();
				MethodInfo setMethod = propertyInfo.GetSetMethod();
				_get = (Func<T, TPropertyType>)ExpressionHelper.CreateTypedFastInvoke((MethodBase)getMethod);
				_set = (Action<T, TPropertyType>)ExpressionHelper.CreateTypedFastInvoke((MethodBase)setMethod);
			}

			public void MoveProperty(object source, object destination)
			{
				TPropertyType arg = _get((T)source);
				_set((T)destination, arg);
			}
		}

		private static readonly Dictionary<Type, ITextComponentManipulator> Manipulators = new Dictionary<Type, ITextComponentManipulator>();

		public static FieldInfo m_ChunkOffset = typeof(StringBuilder).GetField("m_ChunkOffset", BindingFlags.Instance | BindingFlags.NonPublic);

		public static FieldInfo m_ChunkLength = typeof(StringBuilder).GetField("m_ChunkLength", BindingFlags.Instance | BindingFlags.NonPublic);

		public static MethodInfo FindChunkForIndex = typeof(StringBuilder).GetMethod("FindChunkForIndex", BindingFlags.Instance | BindingFlags.NonPublic);

		public static MethodInfo ReplaceAllInChunk = typeof(StringBuilder).GetMethod("ReplaceAllInChunk", BindingFlags.Instance | BindingFlags.NonPublic);

		public static MethodInfo StartsWith = typeof(StringBuilder).GetMethod("StartsWith", BindingFlags.Instance | BindingFlags.NonPublic);

		private static List<IPropertyMover> TexturePropertyMovers;

		private static readonly string SetAllDirtyMethodName = "SetAllDirty";

		private static readonly string TexturePropertyName = "texture";

		private static readonly string MainTexturePropertyName = "mainTexture";

		private static readonly string CapitalMainTexturePropertyName = "MainTexture";

		private static readonly string MarkAsChangedMethodName = "MarkAsChanged";

		private static readonly string SupportRichTextPropertyName = "supportRichText";

		private static readonly string RichTextPropertyName = "richText";

		public static FieldInfo m_AtlasPopulationMode = typeof(TMP_FontAsset).GetField("m_AtlasPopulationMode", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_SourceFontFile = typeof(TMP_FontAsset).GetField("m_SourceFontFile", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_FaceInfo = typeof(TMP_FontAsset).GetField("m_FaceInfo", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo s_MissingCharacterList = typeof(TMP_FontAsset).GetField("s_MissingCharacterList", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_MissingUnicodesFromFontFile = typeof(TMP_FontAsset).GetField("m_MissingUnicodesFromFontFile", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_CharacterLookupDictionary = typeof(TMP_FontAsset).GetField("m_CharacterLookupDictionary", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_CharacterTable = typeof(TMP_FontAsset).GetField("m_CharacterTable", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo m_CharactersToAddLookup = typeof(TMP_FontAsset).GetField("m_CharactersToAddLookup", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static Type GetUnityType(this object obj)
		{
			return obj.GetType();
		}

		private static bool IsWordChar(char c)
		{
			return char.IsLetterOrDigit(c) || c == '_';
		}

		public static bool Contains(this string s, string value, bool ignoreCase = false)
		{
			return ignoreCase ? (s.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) : (s.IndexOf(value, StringComparison.Ordinal) >= 0);
		}

		public static string ToString(this char[] value, int startIndex, int count)
		{
			if (value == null)
			{
				throw new ArgumentNullException("value");
			}
			if (startIndex < 0 || startIndex > value.Length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex + count > value.Length)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			return new string(value, startIndex, count);
		}

		public static StringBuilder ReplaceFull(this StringBuilder builder, string oldValue, string newValue)
		{
			return builder.ReplaceFull(oldValue, newValue, 0, builder.Length);
		}

		private static StringBuilder ReplaceFull(this StringBuilder builder, string oldValue, string newValue, int startIndex, int count)
		{
			int length = builder.Length;
			if ((uint)startIndex > (uint)length)
			{
				throw new ArgumentOutOfRangeException("startIndex");
			}
			if (count < 0 || startIndex > length - count)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			if (oldValue == null)
			{
				throw new ArgumentNullException("oldValue");
			}
			if (oldValue.Length == 0)
			{
				throw new ArgumentException("oldValue");
			}
			if (newValue == null)
			{
				newValue = "";
			}
			int num = newValue.Length - oldValue.Length;
			int[] array = null;
			int num2 = 0;
			StringBuilder stringBuilder = (StringBuilder)FindChunkForIndex.Invoke(builder, new object[1] { startIndex });
			int num3 = startIndex - (int)m_ChunkOffset.GetValue(builder);
			while (count > 0)
			{
				if ((num3 == 0 || !IsWordChar(stringBuilder[num3 - 1])) && (bool)StartsWith.Invoke(builder, new object[4] { stringBuilder, num3, count, oldValue }))
				{
					int num4 = num3 + oldValue.Length;
					if (num4 == length || !IsWordChar(stringBuilder[num4]))
					{
						if (array == null)
						{
							array = new int[5];
						}
						else if (num2 >= array.Length)
						{
							int[] array2 = new int[array.Length * 3 / 2 + 4];
							Array.Copy(array, array2, array.Length);
							array = array2;
						}
						array[num2++] = num3;
					}
					num3 += oldValue.Length;
					count -= oldValue.Length;
				}
				else
				{
					num3++;
					count--;
				}
				if (num3 >= (int)m_ChunkLength.GetValue(stringBuilder) || count == 0)
				{
					int num5 = num3 + (int)m_ChunkOffset.GetValue(stringBuilder);
					int num6 = num5;
					ReplaceAllInChunk.Invoke(builder, new object[5] { array, num2, stringBuilder, oldValue.Length, newValue });
					num5 += (newValue.Length - oldValue.Length) * num2;
					num2 = 0;
					stringBuilder = (StringBuilder)FindChunkForIndex.Invoke(builder, new object[1] { num5 });
					num3 = num5 - (int)m_ChunkOffset.GetValue(stringBuilder);
				}
			}
			return builder;
		}

		public static StringBuilder ReplaceFullWords(this StringBuilder s, string oldWord, string newWord, bool ignoreCase = false)
		{
			if (s == null)
			{
				return null;
			}
			string input = s.ToString();
			string pattern = "(?<=^|\\W)" + Regex.Escape(oldWord) + "(?=$|\\W)";
			string value = Regex.Replace(input, pattern, newWord, ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
			return s.Clear().Append(value);
		}

		public static string ReplaceFullWords(this string s, string oldWord, string newWord, bool ignoreCase = false)
		{
			if (s == null)
			{
				return null;
			}
			string pattern = "(?<=^|\\W)" + Regex.Escape(oldWord) + "(?=$|\\W)";
			return Regex.Replace(s, pattern, newWord, ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None);
		}

		public static bool EqualsIgnoreCase(this string value, string other)
		{
			return string.Equals(value, other, StringComparison.OrdinalIgnoreCase);
		}

		public static Texture2D GetTexture(this object ui)
		{
			if (ui == null)
			{
				return null;
			}
			SpriteRenderer val = default(SpriteRenderer);
			if (!ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val))
			{
				Type type = ui.GetType();
				CachedProperty val2 = ReflectionCache.CachedProperty(type, MainTexturePropertyName);
				object obj;
				if ((obj = ((val2 != null) ? val2.Get(ui) : null)) == null)
				{
					CachedProperty val3 = ReflectionCache.CachedProperty(type, TexturePropertyName);
					if ((obj = ((val3 != null) ? val3.Get(ui) : null)) == null)
					{
						CachedProperty val4 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName);
						obj = ((val4 != null) ? val4.Get(ui) : null);
					}
				}
				return (Texture2D)((obj is Texture2D) ? obj : null);
			}
			Sprite sprite = val.sprite;
			if ((Object)(object)sprite == (Object)null)
			{
				return null;
			}
			return sprite.texture;
		}

		public static string GetTextureName(this object texture, string fallbackName)
		{
			Texture2D val = default(Texture2D);
			if (ObjectExtensions.TryCastTo<Texture2D>(texture, ref val))
			{
				string name = ((Object)val).name;
				if (!string.IsNullOrEmpty(name))
				{
					return name;
				}
			}
			return fallbackName;
		}

		private static byte[] EncodeToPNGEx(Texture2D texture)
		{
			if (ImageConversion_Methods.EncodeToPNG != null)
			{
				return ImageConversion_Methods.EncodeToPNG(texture);
			}
			if (Texture2D_Methods.EncodeToPNG != null)
			{
				return Texture2D_Methods.EncodeToPNG(texture);
			}
			throw new NotSupportedException("No way to encode the texture to PNG.");
		}

		public static Sprite SetTexture(this object ui, Texture2D texture, Sprite sprite, bool isPrefixHooked)
		{
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			if (ui == null)
			{
				return null;
			}
			Texture2D texture2 = ui.GetTexture();
			if (!UnityObjectReferenceComparer.Default.Equals((object)texture2, (object)texture))
			{
				SpriteRenderer sr = null;
				Sprite val = null;
				if (ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref sr))
				{
					if (isPrefixHooked)
					{
						return SafeCreateSprite(sr, sprite, texture);
					}
					return SafeSetSprite(sr, sprite, texture);
				}
				Type type = ui.GetType();
				CachedProperty val2 = ReflectionCache.CachedProperty(type, MainTexturePropertyName);
				if (val2 != null)
				{
					val2.Set(ui, (object)texture);
				}
				CachedProperty val3 = ReflectionCache.CachedProperty(type, TexturePropertyName);
				if (val3 != null)
				{
					val3.Set(ui, (object)texture);
				}
				CachedProperty val4 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName);
				if (val4 != null)
				{
					val4.Set(ui, (object)texture);
				}
				CachedProperty val5 = ReflectionCache.CachedProperty(type, "material");
				object obj = ((val5 != null) ? val5.Get(ui) : null);
				if (obj != null)
				{
					CachedProperty val6 = ReflectionCache.CachedProperty(obj.GetType(), MainTexturePropertyName);
					if ((Object)(Texture2D)((val6 != null) ? val6.Get(obj) : null) == (Object)(object)texture2 && val6 != null)
					{
						val6.Set(obj, (object)texture);
					}
				}
			}
			return null;
		}

		public static Sprite SafeSetSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture)
		{
			//IL_0019: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			return sr.sprite = Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero);
		}

		public static bool IsComponentActive(this object ui)
		{
			Component val = (Component)((ui is Component) ? ui : null);
			if ((Object)(object)val != (Object)null && Object.op_Implicit((Object)(object)val))
			{
				GameObject gameObject = val.gameObject;
				if (Object.op_Implicit((Object)(object)gameObject))
				{
					Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
					if ((Object)(object)val2 != (Object)null)
					{
						return gameObject.activeInHierarchy && val2.enabled;
					}
					return gameObject.activeInHierarchy;
				}
			}
			return true;
		}

		public static TextureDataResult GetTextureData(this Texture2D texture)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			int width = ((Texture)texture).width;
			int height = ((Texture)texture).height;
			byte[] array = null;
			if (array == null)
			{
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)0);
				GL.Clear(false, true, new Color(0f, 0f, 0f, 0f));
				Graphics.Blit((Texture)(object)texture, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height);
				val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0);
				array = EncodeToPNGEx(val);
				Object.DestroyImmediate((Object)(object)val);
				RenderTexture.active = (((Object)(object)active == (Object)(object)temporary) ? null : active);
				RenderTexture.ReleaseTemporary(temporary);
			}
			float realtimeSinceStartup2 = Time.realtimeSinceStartup;
			return new TextureDataResult(array, nonReadable: false, realtimeSinceStartup2 - realtimeSinceStartup);
		}

		public static bool IsCompatible(this object texture, ImageFormat dataType)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			TextureFormat format = ((Texture2D)texture).format;
			return dataType switch
			{
				ImageFormat.TGA => (int)format == 5 || (int)format == 4 || (int)format == 3, 
				ImageFormat.PNG => true, 
				_ => false, 
			};
		}

		public static bool IsKnownImageType(this object ui)
		{
			if (ui == null)
			{
				return false;
			}
			Type unityType = ui.GetUnityType();
			Material val = default(Material);
			SpriteRenderer val2 = default(SpriteRenderer);
			if (!ObjectExtensions.TryCastTo<Material>(ui, ref val) && !ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val2) && (UnityTypes.Image == null || !UnityTypes.Image.IsAssignableFrom(unityType)) && (UnityTypes.RawImage == null || !UnityTypes.RawImage.IsAssignableFrom(unityType)) && (UnityTypes.CubismRenderer == null || !UnityTypes.CubismRenderer.IsAssignableFrom(unityType)))
			{
				if (UnityTypes.UIWidget != null)
				{
					object objA = unityType;
					TypeContainer uILabel = UnityTypes.UILabel;
					if (!object.Equals(objA, (uILabel != null) ? uILabel.UnityType : null) && UnityTypes.UIWidget.IsAssignableFrom(unityType))
					{
						return true;
					}
				}
				if ((UnityTypes.UIAtlas == null || !UnityTypes.UIAtlas.IsAssignableFrom(unityType)) && (UnityTypes.UITexture == null || !UnityTypes.UITexture.IsAssignableFrom(unityType)))
				{
					return UnityTypes.UIPanel != null && UnityTypes.UIPanel.IsAssignableFrom(unityType);
				}
			}
			return true;
		}

		public static TextureTranslationInfo GetOrCreateTextureTranslationInfo(this Texture2D texture)
		{
			TextureTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<TextureTranslationInfo>((object)texture);
			orCreateExtensionData.Initialize(texture);
			return orCreateExtensionData;
		}

		public static ITextComponentManipulator GetTextManipulator(this object ui)
		{
			if (ui == null)
			{
				return null;
			}
			Type unityType = ui.GetUnityType();
			if (!Manipulators.TryGetValue(unityType, out var value))
			{
				value = ((UnityTypes.TextField != null && UnityTypes.TextField.IsAssignableFrom(unityType)) ? new FairyGUITextComponentManipulator() : ((UnityTypes.TextArea2D != null && UnityTypes.TextArea2D.IsAssignableFrom(unityType)) ? new TextArea2DComponentManipulator() : ((UnityTypes.UguiNovelText == null || !UnityTypes.UguiNovelText.IsAssignableFrom(unityType)) ? ((ITextComponentManipulator)new DefaultTextComponentManipulator(ui.GetType())) : ((ITextComponentManipulator)new UguiNovelTextComponentManipulator(ui.GetType())))));
				Manipulators[unityType] = value;
			}
			return value;
		}

		private static Sprite SafeCreateSprite(Sprite sprite, Texture2D texture)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = sprite.rect;
			float x = ((Rect)(ref rect)).x;
			rect = sprite.rect;
			return Sprite.Create(texture, new Rect(x, ((Rect)(ref rect)).y, (float)((Texture)texture).width, (float)((Texture)texture).height), sprite.pivot);
		}

		private static Sprite SafeCreateSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture)
		{
			//IL_0019: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero);
		}

		public static void SetAllDirtyEx(this object ui)
		{
			if (ui == null)
			{
				return;
			}
			Type unityType = ui.GetUnityType();
			SpriteRenderer val = default(SpriteRenderer);
			if (UnityTypes.Graphic != null && UnityTypes.Graphic.IsAssignableFrom(unityType))
			{
				ReflectionCache.CachedMethod(UnityTypes.Graphic.ClrType, SetAllDirtyMethodName).Invoke(ui);
			}
			else if (!ObjectExtensions.TryCastTo<SpriteRenderer>(ui, ref val))
			{
				MethodInfo methodInfo = AccessToolsShim.Method(ui.GetType(), MarkAsChangedMethodName, new Type[0]);
				if (!(methodInfo == null))
				{
					methodInfo.Invoke(ui, null);
				}
			}
		}

		public static bool ShouldIgnoreTextComponent(this object ui)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			Component val = (Component)((ui is Component) ? ui : null);
			if ((Object)(object)val == (Object)null || !Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			GameObject gameObject = val.gameObject;
			Component firstComponentInSelfOrAncestor;
			if (UnityTypes.InputField != null)
			{
				GameObject gameObject2 = val.gameObject;
				TypeContainer inputField = UnityTypes.InputField;
				firstComponentInSelfOrAncestor = gameObject2.GetFirstComponentInSelfOrAncestor((inputField != null) ? inputField.UnityType : null);
				if ((Object)(object)firstComponentInSelfOrAncestor != (Object)null && InputField_Properties.Placeholder != null)
				{
					Component val2 = (Component)InputField_Properties.Placeholder.Get((object)firstComponentInSelfOrAncestor);
					return !UnityObjectReferenceComparer.Default.Equals((object)val2, (object)val);
				}
			}
			if (UnityTypes.TMP_InputField != null)
			{
				GameObject gameObject3 = val.gameObject;
				TypeContainer tMP_InputField = UnityTypes.TMP_InputField;
				firstComponentInSelfOrAncestor = gameObject3.GetFirstComponentInSelfOrAncestor((tMP_InputField != null) ? tMP_InputField.UnityType : null);
				if ((Object)(object)firstComponentInSelfOrAncestor != (Object)null && TMP_InputField_Properties.Placeholder != null)
				{
					Component val3 = (Component)TMP_InputField_Properties.Placeholder.Get((object)firstComponentInSelfOrAncestor);
					return !UnityObjectReferenceComparer.Default.Equals((object)val3, (object)val);
				}
			}
			GameObject go = gameObject;
			TypeContainer uIInput = UnityTypes.UIInput;
			firstComponentInSelfOrAncestor = go.GetFirstComponentInSelfOrAncestor((uIInput != null) ? uIInput.UnityType : null);
			return (Object)(object)firstComponentInSelfOrAncestor != (Object)null;
		}

		public static Component GetFirstComponentInSelfOrAncestor(this GameObject go, Type type)
		{
			if (type == null)
			{
				return null;
			}
			GameObject val = go;
			while ((Object)(object)val != (Object)null)
			{
				Component component = val.GetComponent(type);
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
				Transform transform = val.transform;
				GameObject val2;
				if ((Object)(object)transform == (Object)null)
				{
					val2 = null;
				}
				else
				{
					Transform parent = transform.parent;
					val2 = (((Object)(object)parent != (Object)null) ? ((Component)parent).gameObject : null);
				}
				val = val2;
			}
			return null;
		}

		public static ImageTranslationInfo GetOrCreateImageTranslationInfo(this object obj, Texture2D originalTexture)
		{
			if (obj == null)
			{
				return null;
			}
			ImageTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<ImageTranslationInfo>(obj);
			if (orCreateExtensionData.Original == null)
			{
				orCreateExtensionData.Initialize(originalTexture);
			}
			return orCreateExtensionData;
		}

		public static void Load()
		{
			TexturePropertyMovers = new List<IPropertyMover>();
			LoadProperty<Object, string>("name");
			LoadProperty<Texture, int>("anisoLevel");
			LoadProperty<Texture, FilterMode>("filterMode");
			LoadProperty<Texture, float>("mipMapBias");
			LoadProperty<Texture, TextureWrapMode>("wrapMode");
		}

		private static void LoadProperty<TObject, TPropertyType>(string propertyName)
		{
			PropertyInfo property = typeof(TObject).GetProperty(propertyName);
			if (property != null && property.CanWrite && property.CanRead)
			{
				TexturePropertyMovers.Add(new PropertyMover<TObject, TPropertyType>(property));
			}
		}

		public static void LoadImageEx(this Texture2D texture, Texture2D originalTexture)
		{
			if (!((Object)(object)originalTexture != (Object)null))
			{
				return;
			}
			foreach (IPropertyMover texturePropertyMover in TexturePropertyMovers)
			{
				texturePropertyMover.MoveProperty(originalTexture, texture);
			}
		}

		public static TextTranslationInfo GetOrCreateTextTranslationInfo(this object ui)
		{
			TextTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData<TextTranslationInfo>(ui);
			orCreateExtensionData.Init(ui);
			return orCreateExtensionData;
		}

		public static void SetText(this object ui, string text, TextTranslationInfo info)
		{
			if (ui != null)
			{
				info?.TextManipulator.SetText(ui, text);
			}
		}

		public static string GetText(this object ui, TextTranslationInfo info)
		{
			if (ui == null)
			{
				return null;
			}
			return info?.TextManipulator.GetText(ui);
		}

		public static void TryRemoveCharacter(this TMP_FontAsset fontAsset, uint unicode)
		{
			((List<uint>)s_MissingCharacterList.GetValue(fontAsset)).Add(unicode);
			((HashSet<uint>)m_MissingUnicodesFromFontFile.GetValue(fontAsset)).Add(unicode);
			((HashSet<uint>)m_CharactersToAddLookup.GetValue(fontAsset)).Remove(unicode);
			((Dictionary<uint, TMP_Character>)m_CharacterLookupDictionary.GetValue(fontAsset)).Remove(unicode);
			((List<TMP_Character>)m_CharacterTable.GetValue(fontAsset)).RemoveAll((TMP_Character character) => ((TMP_TextElement)character).unicode == unicode);
		}

		public static void TryRemoveCharacters(this TMP_FontAsset fontAsset, uint[] unicodes)
		{
			for (int i = 0; i < unicodes.Length; i++)
			{
				fontAsset.TryRemoveCharacter(unicodes[i]);
			}
		}
	}
}
namespace GameTranslator.Patches
{
	[HarmonyPatch(typeof(GrabbableObject))]
	internal class GrabbableObjectPatcher
	{
		public static Dictionary<string, string> originToTranslated = new Dictionary<string, string>();

		public static HashSet<string> translatedItems = new HashSet<string>();

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void start(ref GrabbableObject __instance)
		{
			if (!((Object)(object)__instance.itemProperties != (Object)null) || !TranslatePlugin.shouldTranslateItems.Value || Utility.IsNullOrWhiteSpace(__instance.itemProperties.itemName))
			{
				return;
			}
			if (!translatedItems.Contains(__instance.itemProperties.itemName))
			{
				originToTranslated[__instance.itemProperties.itemName] = TranslateConfig.replaceByMap(__instance.itemProperties.itemName, TranslateConfig.items);
				translatedItems.Add(originToTranslated[__instance.itemProperties.itemName]);
				__instance.itemProperties.itemName = originToTranslated[__instance.itemProperties.itemName];
			}
			if (originToTranslated.ContainsKey(__instance.itemProperties.itemName))
			{
				__instance.itemProperties.itemName = originToTranslated[__instance.itemProperties.itemName];
			}
			ScanNodeProperties componentInChildren = ((Component)__instance).GetComponentInChildren<ScanNodeProperties>();
			if ((Object)(object)componentInChildren != (Object)null && componentInChildren.headerText != null)
			{
				if (!translatedItems.Contains(componentInChildren.headerText))
				{
					originToTranslated[componentInChildren.headerText] = TranslateConfig.replaceByMap(componentInChildren.headerText, TranslateConfig.items);
					translatedItems.Add(originToTranslated[componentInChildren.headerText]);
					componentInChildren.headerText = originToTranslated[componentInChildren.headerText];
				}
				if (originToTranslated.ContainsKey(componentInChildren.headerText))
				{
					componentInChildren.headerText = originToTranslated[componentInChildren.headerText];
				}
			}
		}
	}
	[HarmonyPatch(typeof(HUDManager))]
	internal class HUDManagerPatcher
	{
		public static TextMeshProUGUI tipText;

		public static bool fadeTipText = false;

		public static TextMeshProUGUI notificationText;

		public static bool fadeNotificationTextt = false;

		public static int tipShowTime = 0;

		public static int notificationShowTime = 0;

		public static FieldInfo scanNodes = typeof(HUDManager).GetField("scanNodes", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo nodesOnScreen = typeof(HUDManager).GetField("nodesOnScreen", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static Dictionary<string, string> originToTranslated = new Dictionary<string, string>();

		public static HashSet<string> translatedItems = new HashSet<string>();

		private static string lastChat = "";

		private static readonly BindingFlags All = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private static MethodInfo CanTipDisplay = typeof(HUDManager).GetMethod("CanTipDisplay", All);

		private static MethodInfo StopCoroutine = typeof(HUDManager).GetMethod("StopCoroutine", All, null, new Type[1] { typeof(IEnumerator) }, null);

		private static MethodInfo StartCoroutine = typeof(HUDManager).GetMethod("StartCoroutine", All, null, new Type[1] { typeof(IEnumerator) }, null);

		private static MethodInfo TipsPanelTimer = typeof(HUDManager).GetMethod("TipsPanelTimer", All);

		private static FieldInfo tipsPanelCoroutine = typeof(HUDManager).GetField("tipsPanelCoroutine", All);

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void start(ref HUDManager __instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance.holdButtonToEndGameEarlyText != (Object)null)
			{
				((Graphic)__instance.holdButtonToEndGameEarlyText).color = Color.yellow;
			}
			GameObject val = new GameObject("TipHUDDisplay");
			val.AddComponent<RectTransform>();
			tipText = val.AddComponent<TextMeshProUGUI>();
			RectTransform rectTransform = ((TMP_Text)tipText).rectTransform;
			((Transform)rectTransform).SetParent(((Component)__instance.PTTIcon).transform, false);
			rectTransform.anchoredPosition = new Vector2(310f, -130f);
			((TMP_Text)tipText).fontSize = 9f;
			((TMP_Text)tipText).overflowMode = (TextOverflowModes)0;
			((Behaviour)tipText).enabled = false;
			notificationText = new GameObject("NotificationHUDDisplay").AddComponent<TextMeshProUGUI>();
			RectTransform component = ((Component)notificationText).gameObject.GetComponent<RectTransform>();
			((Transform)component).SetParent(((Component)__instance.PTTIcon).transform, false);
			component.anchoredPosition = new Vector2(153f, -200f);
			((TMP_Text)notificationText).fontStyle = (FontStyles)1;
			((TMP_Text)notificationText).fontSize = 10f;
			((TMP_Text)notificationText).alignment = (TextAlignmentOptions)514;
			((TMP_Text)notificationText).overflowMode = (TextOverflowModes)0;
			((Behaviour)notificationText).enabled = false;
		}

		[HarmonyPostfix]
		[HarmonyPatch("Update")]
		private static void update(HUDManager __instance)
		{
			if (TranslatePlugin.shouldTranslateHUD.Value && lastChat.Length != ((TMP_Text)__instance.chatText).text.Length)
			{
				((TMP_Text)__instance.chatText).text = TranslateConfig.hudText.TryTranslateByStrong(((TMP_Text)__instance.chatText).text);
			}
			lastChat = ((TMP_Text)__instance.chatText).text;
			if (tipShowTime > 0)
			{
				tipShowTime--;
			}
			else if (((Behaviour)tipText).enabled && !fadeTipText)
			{
				fadeText(tipText, ref fadeTipText, 200f, 0f);
			}
			if (notificationShowTime > 0)
			{
				notificationShowTime--;
			}
			else if (((Behaviour)notificationText).enabled && !fadeNotificationTextt)
			{
				fadeText(notificationText, ref fadeNotificationTextt, 200f, 0f);
			}
		}

		private static void fadeText(TextMeshProUGUI text, ref bool fade, float duration, float newAlpha)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			float a = ((Graphic)text).color.a;
			float num = 0f;
			fade = true;
			while (num < duration)
			{
				num += Time.deltaTime;
				float num2 = Mathf.Lerp(a, newAlpha, num / duration);
				((Graphic)text).color = new Color(((Graphic)text).color.r, ((Graphic)text).color.g, ((Graphic)text).color.b, num2);
			}
			((Behaviour)text).enabled = false;
			fade = false;
		}

		public static void addNotification(string text, int time)
		{
			((TMP_Text)notificationText).text = text;
			((Behaviour)notificationText).enabled = true;
			((TMP_Text)notificationText).alpha = 100f;
			notificationShowTime = time;
		}

		public static void addTip(string text, int time, bool isWarning)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			((Graphic)tipText).color = (isWarning ? Color.red : Color.yellow);
			((TMP_Text)tipText).text = text;
			((Behaviour)tipText).enabled = true;
			((TMP_Text)tipText).alpha = 100f;
			tipShowTime = time;
		}

		[HarmonyPatch("DisplayGlobalNotification")]
		[HarmonyPriority(int.MaxValue)]
		[HarmonyPrefix]
		private static void changeNotification(HUDManager __instance, ref string displayText)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (TranslatePlugin.shouldTranslateHUD.Value)
			{
				displayText = TranslateConfig.hudText.TryTranslateByStrong(displayText);
			}
			if (!TranslatePlugin.shouldFixTipErrors.Value)
			{
				((Graphic)__instance.globalNotificationText).color = Color.white;
				return;
			}
			addNotification(displayText, 300);
			((Behaviour)__instance.globalNotificationAnimator).enabled = false;
			((TMP_Text)__instance.globalNotificationText).text = "";
		}

		[HarmonyPostfix]
		[HarmonyPatch("AddChatMessage")]
		private static void changeChatMessage(HUDManager __instance, string chatMessage, string nameOfUserWhoTyped)
		{
			if (TranslatePlugin.shouldTranslateHUD.Value)
			{
				((TMP_Text)__instance.chatText).text = TranslateConfig.hudText.TryTranslateByStrong(((TMP_Text)__instance.chatText).text);
			}
		}

		[HarmonyPriority(int.MaxValue)]
		[HarmonyPrefix]
		[HarmonyPatch("DisplayTip")]
		private static bool changeTip(HUDManager __instance, ref string headerText, ref string bodyText, bool isWarning = false, bool useSave = false, string prefsKey = "LC_Tip1")
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if ((headerText.ToLower().Contains("mod list") || bodyText.ToLower().Contains("mod list")) && TranslatePlugin.shouldHideModList.Value)
			{
				return false;
			}
			if (TranslatePlugin.shouldTranslateHUD.Value)
			{
				headerText = TranslateConfig.hudText.TryTranslateByStrong(headerText);
				bodyText = TranslateConfig.hudText.TryTranslateByStrong(bodyText);
			}
			if (TranslatePlugin.shouldFixTipErrors.Value)
			{
				return addTip(__instance, headerText, bodyText, isWarning, useSave, prefsKey);
			}
			((Graphic)__instance.tipsPanelHeader).color = Color.white;
			((Graphic)__instance.tipsPanelBody).color = Color.white;
			return true;
		}

		private static bool addTip(HUDManager __instance, string headerText, string bodyText, bool isWarning = false, bool useSave = false, string prefsKey = "LC_Tip1")
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and O
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			string text = headerText + "\n" + bodyText;
			try
			{
				if (!(bool)CanTipDisplay.Invoke(__instance, new object[3] { isWarning, useSave, prefsKey }))
				{
					return false;
				}
				if (useSave)
				{
					if ((object)(Coroutine)tipsPanelCoroutine.GetValue(__instance) != null)
					{
						StopCoroutine.Invoke(__instance, new object[1] { tipsPanelCoroutine });
					}
					tipsPanelCoroutine.SetValue(__instance, (object?)(Coroutine)StartCoroutine.Invoke(__instance, new object[1] { (IEnumerator)TipsPanelTimer.Invoke(__instance, new object[1] { prefsKey }) }));
				}
				((Behaviour)__instance.tipsPanelAnimator).enabled = false;
				addTip(text, 320, isWarning);
			}
			catch (Exception ex)
			{
				TranslatePlugin.logger.LogError((object)ex);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Terminal))]
	internal class TerminalPatch
	{
		public class Translator
		{
			public Dictionary<string, TerminalKeyword> keyValuePairs = new Dictionary<string, TerminalKeyword>();

			public Dictionary<string, string> keys = new Dictionary<string, string>();

			public TerminalKeyword getTranslateKey(TerminalKeyword old, bool useC)
			{
				if (!keyValuePairs.ContainsKey(((Object)old).name + old.word))
				{
					if ((useC && !HaveChineseCMD(old.word)) || (!useC && !HavePinyinCMD(old.word)))
					{
						keyValuePairs.Add(((Object)old).name + old.word, old);
						return old;
					}
					string text = (useC ? getChineseCMD(old.word) : getPinyinCMD(old.word));
					if (text == old.word)
					{
						keyValuePairs.Add(((Object)old).name + old.word, old);
						return old;
					}
					TerminalKeyword val = Copy(old);
					val.word = text;
					keyValuePairs.Add(((Object)old).name + old.word, val);
					if (val.compatibleNouns != null)
					{
						List<CompatibleNoun> list = val.compatibleNouns.ToList();
						CompatibleNoun[] compatibleNouns = val.compatibleNouns;
						foreach (CompatibleNoun val2 in compatibleNouns)
						{
							if (!getTranslateKey(val2.noun, useC).word.Equals(val2.noun.word))
							{
								CompatibleNoun val3 = TransReflection<CompatibleNoun>(val2);
								val3.noun = getTranslateKey(val2.noun, useC);
								list.Add(val3);
							}
						}
						val.compatibleNouns = list.ToArray();
					}
					if ((Object)(object)val.defaultVerb != (Object)null && val.defaultVerb.compatibleNouns != null)
					{
						List<CompatibleNoun> list2 = val.defaultVerb.compatibleNouns.ToList();
						CompatibleNoun[] compatibleNouns2 = val.defaultVerb.compatibleNouns;
						foreach (CompatibleNoun val4 in compatibleNouns2)
						{
							if (!getTranslateKey(val4.noun, useC).word.Equals(val4.noun.word))
							{
								CompatibleNoun val5 = TransReflection<CompatibleNoun>(val4);
								val5.noun = getTranslateKey(val4.noun, useC);
								list2.Add(val5);
							}
						}
						val.defaultVerb.compatibleNouns = list2.ToArray();
					}
					return val;
				}
				return keyValuePairs[((Object)old).name + old.word];
			}

			public void getTranslateKey(TerminalKeyword old)
			{
				if (keys.ContainsKey(old.word))
				{
					return;
				}
				keys.Add(old.word, old.word);
				if (old.compatibleNouns != null)
				{
					List<CompatibleNoun> list = old.compatibleNouns.ToList();
					CompatibleNoun[] compatibleNouns = old.compatibleNouns;
					foreach (CompatibleNoun val in compatibleNouns)
					{
						getTranslateKey(val.noun);
					}
				}
				if ((Object)(object)old.defaultVerb != (Object)null && old.defaultVerb.compatibleNouns != null)
				{
					List<CompatibleNoun> list2 = old.defaultVerb.compatibleNouns.ToList();
					CompatibleNoun[] compatibleNouns2 = old.defaultVerb.compatibleNouns;
					foreach (CompatibleNoun val2 in compatibleNouns2)
					{
						getTranslateKey(val2.noun);
					}
				}
			}
		}

		public static FieldInfo hasGottenVerb = typeof(Terminal).GetField("hasGottenVerb", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static FieldInfo hasGottenNoun = typeof(Terminal).GetField("hasGottenNoun", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static bool shouldTranslate = false;

		public static bool noText = false;

		public static int texdAdded = 0;

		public static FieldInfo modifyingText = typeof(Terminal).GetField("modifyingText", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

		public static Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();

		public static TMP_InputField screenText = null;

		public static TextTranslationInfo info;

		public static List<object> ig = new List<object>();

		private static int CheckForPlayerNameCommand(string firstWord, string secondWord)
		{
			if (firstWord == "radar")
			{
				return -1;
			}
			if (secondWord.Length <= 2)
			{
				return -1;
			}
			Debug.Log((object)("first word: " + firstWord + "; second word: " + secondWord));
			List<string> list = new List<string>();
			for (int i = 0; i < StartOfRound.Instance.mapScreen.radarTargets.Count; i++)
			{
				list.Add(StartOfRound.Instance.mapScreen.radarTargets[i].name);
				Debug.Log((object)$"name {i}: {list[i]}");
			}
			secondWord = secondWord.ToLower();
			for (int j = 0; j < list.Count; j++)
			{
				string text = list[j].ToLower();
				if (text == secondWord)
				{
					return j;
				}
			}
			Debug.Log((object)$"Target names length: {list.Count}");
			for (int k = 0; k < list.Count; k++)
			{
				Debug.Log((object)"A");
				string text2 = list[k].ToLower();
				Debug.Log((object)$"Word #{k}: {text2}; length: {text2.Length}");
				for (int num = secondWord.Length; num > 2; num--)
				{
					Debug.Log((object)$"c: {num}");
					Debug.Log((object)secondWord.Substring(0, num));
					if (text2.StartsWith(secondWord.Substring(0, num)))
					{
						return k;
					}
				}
			}
			return -1;
		}

		[HarmonyPostfix]
		[HarmonyPatch("ParseWordOverrideOptions")]
		private static void ParseWordOverrideOptions(string playerWord, CompatibleNoun[] options, ref TerminalNode __result)
		{
			for (int i = 0; i < options.Length; i++)
			{
				for (int num = playerWord.Length; num > 0; num--)
				{
					if (getChineseCMD(options[i].noun.word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
					{
						__result = options[i].result;
						return;
					}
					if (getPinyinCMD(options[i].noun.word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
					{
						__result = options[i].result;
						return;
					}
				}
			}
		}

		[HarmonyPatch("CheckForExactSentences")]
		[HarmonyPostfix]
		private static void CheckForExactSentences(Terminal __instance, string playerWord, ref TerminalKeyword __result)
		{
			for (int i = 0; i < __instance.terminalNodes.allKeywords.Length; i++)
			{
				if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
				{
					__result = __instance.terminalNodes.allKeywords[i];
					break;
				}
				if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
				{
					__result = __instance.terminalNodes.allKeywords[i];
					break;
				}
			}
		}

		private static string RemovePunctuation(string s)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (char c in s)
			{
				if (!char.IsPunctuation(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString().ToLower();
		}

		[HarmonyPostfix]
		[HarmonyPatch("CallFunctionInAccessibleTerminalObject")]
		private static void CallFunctionInAccessibleTerminalObject(Terminal __instance, string word)
		{
			TerminalAccessibleObject[] array = Object.FindObjectsOfType<TerminalAccessibleObject>();
			for (int i = 0; i < array.Length; i++)
			{
				if (getChineseCMD(array[i].objectCode).EqualsIgnoreCase(word) || getPinyinCMD(array[i].objectCode).EqualsIgnoreCase(word))
				{
					Debug.Log((object)"Found accessible terminal object with corresponding string, calling function");
					((object)__instance).GetType().GetField("broadcastedCodeThisFrame", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(TranslateConfig.terminal, true);
					array[i].CallFunctionFromTerminal();
					break;
				}
			}
		}

		[HarmonyPatch("ParseWord")]
		[HarmonyPostfix]
		private static void ParseWord(Terminal __instance, string playerWord, int specificityRequired, ref TerminalKeyword __result)
		{
			if (!TranslatePlugin.TerimalCanUseChinese.Value && !TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value)
			{
				return;
			}
			if (playerWord.Length < specificityRequired)
			{
				__result = null;
				return;
			}
			TerminalKeyword val = null;
			for (int i = 0; i < __instance.terminalNodes.allKeywords.Length; i++)
			{
				if (__instance.terminalNodes.allKeywords[i].isVerb && (bool)hasGottenVerb.GetValue(__instance))
				{
					continue;
				}
				_ = __instance.terminalNodes.allKeywords[i].accessTerminalObjects;
				if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
				{
					__result = __instance.terminalNodes.allKeywords[i];
					return;
				}
				if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).EqualsIgnoreCase(playerWord))
				{
					__result = __instance.terminalNodes.allKeywords[i];
					return;
				}
				if (!((Object)(object)val == (Object)null))
				{
					continue;
				}
				for (int num = playerWord.Length; num > specificityRequired; num--)
				{
					if (getChineseCMD(__instance.terminalNodes.allKeywords[i].word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
					{
						val = __instance.terminalNodes.allKeywords[i];
					}
					if (getPinyinCMD(__instance.terminalNodes.allKeywords[i].word).ToLower().StartsWith(playerWord.Substring(0, num).ToLower()))
					{
						val = __instance.terminalNodes.allKeywords[i];
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				__result = val;
			}
		}

		[HarmonyPatch("ParsePlayerSentence")]
		[HarmonyPostfix]
		private static void customParser(Terminal __instance, ref TerminalNode __result)
		{
			string s = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded);
			s = RemovePunctuation(s);
			string[] array = s.Split(Array.Empty<char>(), StringSplitOptions.RemoveEmptyEntries);
			if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("transmit") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["transmit"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("transmit") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["transmit"]))))
			{
				try
				{
					string text = array[1];
					SignalTranslator val = Object.FindObjectOfType<SignalTranslator>();
					if ((Object)(object)val != (Object)null && Time.realtimeSinceStartup - val.timeLastUsingSignalTranslator > 8f && text.Length > 1)
					{
						if (!((NetworkBehaviour)__instance).IsServer)
						{
							val.timeLastUsingSignalTranslator = Time.realtimeSinceStartup;
						}
						__result = __instance.terminalNodes.specialNodes[22];
						HUDManager.Instance.UseSignalTranslatorServerRpc(text.Substring(0, Mathf.Min(text.Length, 10)));
					}
					return;
				}
				catch (Exception ex)
				{
					TranslateConfig.Log(ex.Message);
					return;
				}
			}
			if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("switch") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["switch"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("switch") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["switch"]))))
			{
				int num = CheckForPlayerNameCommand(array[0], array[1]);
				if (num != -1)
				{
					StartOfRound.Instance.mapScreen.SwitchRadarTargetAndSync(num);
					__result = __instance.terminalNodes.specialNodes[20];
				}
			}
			else if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("ping") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["ping"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("ping") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["ping"]))))
			{
				int num2 = CheckForPlayerNameCommand(array[0], array[1]);
				if (num2 != -1)
				{
					StartOfRound.Instance.mapScreen.PingRadarBooster(num2);
					__result = __instance.terminalNodes.specialNodes[21];
				}
			}
			else if (array.Length > 1 && ((TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey("flash") && array[0].ToLower().Equals(TranslateConfig.cmd_zh.normal["flash"])) || (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey("flash") && array[0].ToLower().Equals(TranslateConfig.cmd_py.normal["flash"]))))
			{
				int num3 = CheckForPlayerNameCommand(array[0], array[1]);
				if (num3 != -1)
				{
					StartOfRound.Instance.mapScreen.FlashRadarBooster(num3);
					__result = __instance.terminalNodes.specialNodes[23];
				}
				else if (StartOfRound.Instance.mapScreen.radarTargets[StartOfRound.Instance.mapScreen.targetTransformIndex].isNonPlayer)
				{
					StartOfRound.Instance.mapScreen.FlashRadarBooster(StartOfRound.Instance.mapScreen.targetTransformIndex);
					__result = __instance.terminalNodes.specialNodes[23];
				}
			}
		}

		private static bool HaveChineseCMD(string name)
		{
			return TranslateConfig.cmd_zh.normal.ContainsKey(name);
		}

		private static bool HavePinyinCMD(string name)
		{
			return TranslateConfig.cmd_py.normal.ContainsKey(name);
		}

		private static string getChineseCMD(string name)
		{
			if (TranslatePlugin.TerimalCanUseChinese.Value && TranslateConfig.cmd_zh.normal.ContainsKey(name))
			{
				return TranslateConfig.cmd_zh.normal[name];
			}
			return "";
		}

		private static string getPinyinCMD(string name)
		{
			if (TranslatePlugin.TerimalCanUsePinyinAbbreviation.Value && TranslateConfig.cmd_py.normal.ContainsKey(name))
			{
				return TranslateConfig.cmd_py.normal[name];
			}
			return "";
		}

		private static string getOrginByChineseCMD(string name)
		{
			if (TranslateConfig.cmd_zh.special.ContainsKey(name))
			{
				return TranslateConfig.cmd_zh.special[name];
			}
			return name;
		}

		private static string getOrginByPinyinCMD(string name)
		{
			if (TranslateConfig.cmd_py.special.ContainsKey(name))
			{
				return TranslateConfig.cmd_py.special[name];
			}
			return name;
		}

		private static T TransReflection<T>(T tIn)
		{
			T val = Activator.CreateInstance<T>();
			foreach (FieldInfo runtimeField in tIn.GetType().GetRuntimeFields())
			{
				val.GetType().GetRuntimeField(runtimeField.Name).SetValue(val, runtimeField.GetValue(tIn));
			}
			return val;
		}

		public static TerminalKeyword Copy(TerminalKeyword oldOne)
		{
			return TransReflection<TerminalKeyword>(oldOne);
		}

		[HarmonyPatch("LoadNewNode")]
		[HarmonyPostfix]
		private static void changeNewNodeText(Terminal __instance, TerminalNode node)
		{
			if (info != null)
			{
				info.Reset(__instance.screenText.text);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch("OnSubmit")]
		private static void changeSubmit(Terminal __instance)
		{
			if (info != null)
			{
				texdAdded = __instance.currentText.Length - info.OriginalText.Length;
				if (texdAdded != 0)
				{
					info.Reset(__instance.currentText);
				}
			}
		}

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void changeUpdateText(Terminal __instance)
		{
			try
			{
				if ((info == null || !info.IsTranslated) && info != null && !info.IsTranslated && TranslatePlugin.shouldTranslateTerimal.Value)
				{
					string translatedText = TranslateConfig.replaceByMap(__instance.currentText, TranslateConfig.terminal);
					info.SetTranslatedText(translatedText);
					SetText(info.TranslatedText, __instance);
					info.OriginalText = __instance.currentText;
				}
			}
			catch (Exception ex)
			{
				TranslatePlugin.logger.LogWarning((object)ex);
			}
		}

		public static void SetText(string text, Terminal Instance)
		{
			if (!((Object)(object)Instance == (Object)null))
			{
				modifyingText.SetValue(Instance, true);
				((Selectable)Instance.screenText).interactable = true;
				Instance.screenText.text = text;
				Instance.currentText = Instance.screenText.text;
				if ((Object)(object)Instance.screenText.verticalScrollbar != (Object)null)
				{
					Instance.screenText.verticalScrollbar.value = 0f;
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void startTerminal(Terminal __instance)
		{
			info = __instance.screenText.GetOrCreateTextTranslationInfo();
			ig.Clear();
			foreach (FieldInfo runtimeField in ((object)__instance).GetType().GetRuntimeFields())
			{
				if (runtimeField.GetValue(__instance) != null && UnityTypes.TMP_Text.IsAssignableFrom(runtimeField.GetValue(__instance).GetType()))
				{
					ig.Add(runtimeField.GetValue(__instance));
				}
			}
			info.MustIgnore = true;
		}
	}
}
namespace GameTranslator.Patches.Translatons
{
	internal class TextTranslationInfo
	{
		private Action<object> _unfont;

		private bool _initialized = false;

		private HashSet<string> _redirectedTranslations;

		public long changeTime = 0L;

		public static TMP_FontAsset origin;

		public ITextComponentManipulator TextManipulator { get; set; }

		public string OriginalText { get; set; }

		public string TranslatedText { get; set; }

		public bool IsTranslated { get; set; }

		public bool IsCurrentlySettingText { get; set; }

		public bool IsStabilizingText { get; set; }

		public bool IsKnownTextComponent { get; set; }

		public bool SupportsStabilization { get; set; }

		public bool ShouldIgnore { get; set; }

		public bool MustIgnore { get; set; }

		public long ChangeTime
		{
			get
			{
				return changeTime;
			}
			set
			{
				changeTime = value;
			}
		}

		public HashSet<string> RedirectedTranslations => _redirectedTranslations ?? (_redirectedTranslations = new HashSet<string>());

		public void Init(object ui)
		{
			i