Decompiled source of LethalCompanyDe v1.0.4
BepInEx/core/Kuriki-LethalCompanyDe/XUnity.Common.dll
Decompiled a year agousing 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/Kuriki-LethalCompanyDe/ExIni.dll
Decompiled a year agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Microsoft.Win32; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyInformationalVersion("GIT master [cf85ca6f3fc361cf48bf56107e4cec9102b7f5eb] ")] [assembly: AssemblyTitle("ExIni")] [assembly: Guid("b8adf1ac-aade-485a-8997-14c4b42e0a8b")] [assembly: AssemblyDescription("Extended INI File Handler")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyFileVersion("1.0.2.1")] [assembly: AssemblyCompany("Usagirei")] [assembly: AssemblyProduct("ExIni")] [assembly: ComVisible(false)] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCopyright("Copyright © Usagirei 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyVersion("1.0.2.1")] namespace ExIni; public class IniComment { public List<string> Comments { get; set; } public IniComment() { Comments = new List<string>(); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Comments.Count; i++) { string text = Comments[i]; string value = ((i < Comments.Count - 1) ? (";" + text + Environment.NewLine) : (";" + text)); stringBuilder.Append(value); } return stringBuilder.ToString(); } public void Append(params string[] comments) { Comments.AddRange(comments); } } public class IniFile { private readonly IniComment _comments; private readonly List<IniSection> _sections; public IniSection this[string sec] => CreateSection(sec); public IniComment Comments => _comments; public List<IniSection> Sections => _sections; public IniFile() { _comments = new IniComment(); _sections = new List<IniSection>(); } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < Sections.Count; i++) { IniSection iniSection = Sections[i]; if (iniSection.Comments.Comments.Any()) { stringBuilder.AppendLine(iniSection.Comments.ToString()); } stringBuilder.AppendLine(iniSection.ToString()); foreach (IniKey key in iniSection.Keys) { if (key.Comments.Comments.Any()) { stringBuilder.AppendLine(key.Comments.ToString()); } stringBuilder.AppendLine(key.ToString()); } if (i < Sections.Count - 1) { stringBuilder.AppendLine(); } } if (Comments.Comments.Any()) { stringBuilder.AppendLine(); stringBuilder.AppendLine(Comments.ToString()); } return stringBuilder.ToString(); } public IniSection CreateSection(string section) { IniSection section2 = GetSection(section); if (section2 != null) { return section2; } IniSection iniSection = new IniSection(section); _sections.Add(iniSection); return iniSection; } public bool DeleteSection(string section) { if (!HasSection(section)) { return false; } Sections.Remove(GetSection(section)); return true; } public IniSection GetSection(string section) { if (!HasSection(section)) { return null; } return _sections.FirstOrDefault((IniSection iniSection) => iniSection.Section == section); } public bool HasSection(string section) { return _sections.Any((IniSection iniSection) => iniSection.Section == section); } public void Merge(IniFile ini) { Comments.Append(ini.Comments.Comments.ToArray()); foreach (IniSection section in ini.Sections) { IniSection iniSection = this[section.Section]; iniSection.Comments.Append(section.Comments.Comments.ToArray()); foreach (IniKey key in section.Keys) { IniKey iniKey = iniSection[key.Key]; iniKey.Comments.Append(key.Comments.Comments.ToArray()); iniKey.Value = key.Value; } } } public void Save(string filePath) { string directoryName = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } File.WriteAllText(filePath, ToString(), Encoding.UTF8); } public static IniFile FromFile(string iniString) { return IniParser.Parse(File.ReadAllText(iniString)); } public static IniFile FromString(string iniString) { return IniParser.Parse(iniString); } } public class IniKey { private readonly IniComment _comments; public IniComment Comments => _comments; public string Key { get; set; } public string RawValue { get; set; } public string Value { get { return Resolve(RawValue); } set { RawValue = value; } } public IniKey(string key, string value = null) { Key = key; Value = value; _comments = new IniComment(); } public override string ToString() { return $"{Key}={RawValue}"; } private static string GetEnvironment(string env) { return Environment.ExpandEnvironmentVariables(env); } private static string GetRegistry(string path) { string directoryName = Path.GetDirectoryName(path); string fileName = Path.GetFileName(path); if (string.IsNullOrEmpty(directoryName)) { return null; } return Registry.GetValue(directoryName, fileName, string.Empty)?.ToString(); } private static string Resolve(string value) { if (value == null) { return null; } Regex regex = new Regex("\\$\\((?<reg>.*)\\)"); Regex regex2 = new Regex("%.*%"); while (regex.IsMatch(value) || regex2.IsMatch(value)) { value = regex.Replace(value, (Match match) => GetRegistry(match.Groups["reg"].Value)); value = GetEnvironment(value); } return value; } } internal class IniParser { private static readonly Regex CommentRegex = new Regex("^;(?<com>.*)"); private static readonly Regex KeyRegex = new Regex("^(?<key>[\\w\\s]+)=(?<val>.*)$"); private static readonly Regex SectionRegex = new Regex("^\\[(?<sec>[\\w\\s]+)\\]$"); private static readonly Regex VarRegex = new Regex("^\\@(?<key>[\\w\\s]+)=(?<val>.*)$"); public static IniFile Parse(string iniString) { IniFile iniFile = new IniFile(); string[] array = (from line in iniString.Split(new char[1] { '\n' }) let trimmed = line.Trim() select trimmed.TrimEnd(new char[1] { '\r' })).ToArray(); List<string> list = new List<string>(); IniSection iniSection = null; bool flag = false; for (int i = 0; i < array.Length; i++) { string text = array[i]; if (string.IsNullOrEmpty(text)) { continue; } if (IsComment(text)) { string comment = GetComment(text); list.Add(comment); if (IsVariable(comment)) { string[] variable = GetVariable(comment); string variable2 = variable[0]; string value = variable[1]; Environment.SetEnvironmentVariable(variable2, value); } flag = true; } else if (IsSection(text)) { iniSection = iniFile[GetSection(text)]; if (flag) { iniSection.Comments.Append(list.ToArray()); list.Clear(); flag = false; } } else if (IsKey(text)) { if (iniSection == null) { throw new Exception($"{i}: Sectionless Key Value Pair"); } string[] key = GetKey(text); string key2 = key[0]; string value2 = key[1]; if (flag) { iniSection[key2].Comments.Append(list.ToArray()); list.Clear(); flag = false; } iniSection[key2].Value = value2; } } if (flag) { iniFile.Comments.Append(list.ToArray()); } return iniFile; } private static string GetComment(string line) { return CommentRegex.Match(line).Groups["com"].Value; } private static string[] GetKey(string line) { Match match = KeyRegex.Match(line); return new string[2] { match.Groups["key"].Value, match.Groups["val"].Value }; } private static string GetSection(string line) { return SectionRegex.Match(line).Groups["sec"].Value; } private static string[] GetVariable(string line) { Match match = VarRegex.Match(line); return new string[2] { match.Groups["key"].Value, match.Groups["val"].Value }; } private static bool IsComment(string line) { return CommentRegex.IsMatch(line); } private static bool IsKey(string line) { return KeyRegex.IsMatch(line); } private static bool IsSection(string line) { return SectionRegex.IsMatch(line); } private static bool IsVariable(string line) { return VarRegex.IsMatch(line); } } public class IniSection { private readonly IniComment _comments; private readonly List<IniKey> _keys; public IniKey this[string key] => CreateKey(key); public IniComment Comments => _comments; public List<IniKey> Keys => _keys; public string Section { get; set; } public IniSection(string section) { Section = section; _comments = new IniComment(); _keys = new List<IniKey>(); } public override string ToString() { return $"[{Section}]"; } public IniKey CreateKey(string key) { IniKey key2 = GetKey(key); if (key2 != null) { return key2; } IniKey iniKey = new IniKey(key); _keys.Add(iniKey); return iniKey; } public IniKey GetKey(string key) { if (!HasKey(key)) { return null; } return _keys.FirstOrDefault((IniKey iniKey) => iniKey.Key == key); } public bool HasKey(string key) { return _keys.Any((IniKey iniKey) => iniKey.Key == key); } public bool DeleteKey(string key) { if (!HasKey(key)) { return false; } Keys.Remove(GetKey(key)); return true; } }
BepInEx/plugins/Kuriki-LethalCompanyDe/XUnity.AutoTranslator.Plugin.BepInEx.dll
Decompiled a year agousing System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using ExIni; using XUnity.AutoTranslator.Plugin.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("XUnity.AutoTranslator.Plugin.BepInEx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("5.3.0.0")] [assembly: AssemblyInformationalVersion("5.3.0")] [assembly: AssemblyProduct("XUnity.AutoTranslator.Plugin.BepInEx")] [assembly: AssemblyTitle("XUnity.AutoTranslator.Plugin.BepInEx")] [assembly: AssemblyVersion("5.3.0.0")] namespace XUnity.AutoTranslator.Plugin.BepInEx; [BepInPlugin("gravydevsupreme.xunity.autotranslator", "XUnity Auto Translator", "5.3.0")] public class AutoTranslatorPlugin : BaseUnityPlugin, IPluginEnvironment { private IniFile _file; private string _configPath; public IniFile Preferences => _file ?? (_file = ReloadConfig()); public string ConfigPath { get; } public string TranslationPath { get; } public bool AllowDefaultInitializeHarmonyDetourBridge => false; public AutoTranslatorPlugin() { ConfigPath = Paths.ConfigPath; TranslationPath = Paths.BepInExRootPath; _configPath = Path.Combine(ConfigPath, "AutoTranslatorConfig.ini"); } public IniFile ReloadConfig() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(_configPath)) { return (IniFile)(((object)_file) ?? ((object)new IniFile())); } IniFile val = IniFile.FromFile(_configPath); if (_file == null) { return _file = val; } _file.Merge(val); return _file; } public void SaveConfig() { _file.Save(_configPath); } private void Awake() { PluginLoader.LoadWithConfig((IPluginEnvironment)(object)this); } }
BepInEx/plugins/Kuriki-LethalCompanyDe/XUnity.AutoTranslator.Plugin.Core.dll
Decompiled a year ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Cache; using System.Net.Security; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using DynamicLinq; using ExIni; using Harmony; using ICSharpCode.SharpZipLib.Checksums; using ICSharpCode.SharpZipLib.Core; using ICSharpCode.SharpZipLib.Encryption; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using UnityEngine; using UnityEngine.SceneManagement; using XUnity.AutoTranslator.Plugin.Core.AssetRedirection; using XUnity.AutoTranslator.Plugin.Core.Configuration; using XUnity.AutoTranslator.Plugin.Core.Debugging; using XUnity.AutoTranslator.Plugin.Core.Endpoints; using XUnity.AutoTranslator.Plugin.Core.Extensions; using XUnity.AutoTranslator.Plugin.Core.Fonts; using XUnity.AutoTranslator.Plugin.Core.Hooks; using XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI; using XUnity.AutoTranslator.Plugin.Core.Hooks.TextMeshPro; using XUnity.AutoTranslator.Plugin.Core.Hooks.UGUI; using XUnity.AutoTranslator.Plugin.Core.Managed.Textures; using XUnity.AutoTranslator.Plugin.Core.Parsing; using XUnity.AutoTranslator.Plugin.Core.Properties; using XUnity.AutoTranslator.Plugin.Core.Shims; using XUnity.AutoTranslator.Plugin.Core.Text; using XUnity.AutoTranslator.Plugin.Core.Textures; using XUnity.AutoTranslator.Plugin.Core.UI; using XUnity.AutoTranslator.Plugin.Core.UIResize; using XUnity.AutoTranslator.Plugin.Core.Utilities; using XUnity.AutoTranslator.Plugin.Core.Web; using XUnity.AutoTranslator.Plugin.Core.Web.Internal; using XUnity.AutoTranslator.Plugin.ExtProtocol; using XUnity.AutoTranslator.Plugin.Utilities; using XUnity.Common.Constants; using XUnity.Common.Extensions; using XUnity.Common.Harmony; using XUnity.Common.Logging; using XUnity.Common.MonoMod; using XUnity.Common.Utilities; using XUnity.ResourceRedirector; [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("XUnity.AutoTranslator.Plugin.Core")] [assembly: AssemblyProduct("XUnity.AutoTranslator.Plugin.Core")] [assembly: AssemblyInformationalVersion("5.3.0")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyDescription("Main development dependency for XUnity Auto Translator.")] [assembly: AssemblyFileVersion("5.3.0.0")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCompany("gravydevsupreme")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core.Tests")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("5.3.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DynamicLinq { internal static class DynamicQueryable { public static IQueryable<T> Where<T>(this IQueryable<T> source, string predicate, params object[] values) { return (IQueryable<T>)((IQueryable)source).Where(predicate, values); } public static IQueryable Where(this IQueryable source, string predicate, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } LambdaExpression expression = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Where", new Type[1] { source.ElementType }, source.Expression, Expression.Quote(expression))); } public static IQueryable Select(this IQueryable source, string selector, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (selector == null) { throw new ArgumentNullException("selector"); } LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, selector, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[2] { source.ElementType, lambdaExpression.Body.Type }, source.Expression, Expression.Quote(lambdaExpression))); } public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering, params object[] values) { return (IQueryable<T>)((IQueryable)source).OrderBy(ordering, values); } public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (ordering == null) { throw new ArgumentNullException("ordering"); } ParameterExpression[] parameters = new ParameterExpression[1] { Expression.Parameter(source.ElementType, "") }; IEnumerable<DynamicOrdering> enumerable = new ExpressionParser(parameters, ordering, values).ParseOrdering(); Expression expression = source.Expression; string text = "OrderBy"; string text2 = "OrderByDescending"; foreach (DynamicOrdering item in enumerable) { expression = Expression.Call(typeof(Queryable), item.Ascending ? text : text2, new Type[2] { source.ElementType, item.Selector.Type }, expression, Expression.Quote(Expression.Lambda(item.Selector, parameters))); text = "ThenBy"; text2 = "ThenByDescending"; } return source.Provider.CreateQuery(expression); } public static IQueryable Take(this IQueryable source, int count) { if (source == null) { throw new ArgumentNullException("source"); } return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Take", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count))); } public static IQueryable Skip(this IQueryable source, int count) { if (source == null) { throw new ArgumentNullException("source"); } return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Skip", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count))); } public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (keySelector == null) { throw new ArgumentNullException("keySelector"); } if (elementSelector == null) { throw new ArgumentNullException("elementSelector"); } LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values); LambdaExpression lambdaExpression2 = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "GroupBy", new Type[3] { source.ElementType, lambdaExpression.Body.Type, lambdaExpression2.Body.Type }, source.Expression, Expression.Quote(lambdaExpression), Expression.Quote(lambdaExpression2))); } public static bool Any(this IQueryable source) { if (source == null) { throw new ArgumentNullException("source"); } return (bool)source.Provider.Execute(Expression.Call(typeof(Queryable), "Any", new Type[1] { source.ElementType }, source.Expression)); } public static int Count(this IQueryable source) { if (source == null) { throw new ArgumentNullException("source"); } return (int)source.Provider.Execute(Expression.Call(typeof(Queryable), "Count", new Type[1] { source.ElementType }, source.Expression)); } } internal abstract class DynamicClass { public override string ToString() { PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); for (int i = 0; i < properties.Length; i++) { if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append(properties[i].Name); stringBuilder.Append("="); stringBuilder.Append(properties[i].GetValue(this, null)); } stringBuilder.Append("}"); return stringBuilder.ToString(); } } internal class DynamicProperty { private string name; private Type type; public string Name => name; public Type Type => type; public DynamicProperty(string name, Type type) { if (name == null) { throw new ArgumentNullException("name"); } if ((object)type == null) { throw new ArgumentNullException("type"); } this.name = name; this.type = type; } } internal static class DynamicExpression { public static Expression Parse(Type resultType, string expression, params object[] values) { return new ExpressionParser(null, expression, values).Parse(resultType); } public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values) { return ParseLambda(new ParameterExpression[1] { Expression.Parameter(itType, "") }, resultType, expression, values); } public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values) { return Expression.Lambda(new ExpressionParser(parameters, expression, values).Parse(resultType), parameters); } public static Expression<Func<T, S>> ParseLambda<T, S>(string expression, params object[] values) { return (Expression<Func<T, S>>)ParseLambda(typeof(T), typeof(S), expression, values); } public static Type CreateClass(params DynamicProperty[] properties) { throw new NotImplementedException(); } public static Type CreateClass(IEnumerable<DynamicProperty> properties) { throw new NotImplementedException(); } } internal class DynamicOrdering { public Expression Selector; public bool Ascending; } internal class Signature : IEquatable<Signature> { public DynamicProperty[] properties; public int hashCode; public Signature(IEnumerable<DynamicProperty> properties) { this.properties = properties.ToArray(); hashCode = 0; foreach (DynamicProperty property in properties) { hashCode ^= property.Name.GetHashCode() ^ property.Type.GetHashCode(); } } public override int GetHashCode() { return hashCode; } public override bool Equals(object obj) { if (!(obj is Signature)) { return false; } return Equals((Signature)obj); } public bool Equals(Signature other) { if (properties.Length != other.properties.Length) { return false; } for (int i = 0; i < properties.Length; i++) { if (properties[i].Name != other.properties[i].Name || (object)properties[i].Type != other.properties[i].Type) { return false; } } return true; } } internal sealed class ParseException : Exception { private int position; public int Position => position; public ParseException(string message, int position) : base(message) { this.position = position; } public override string ToString() { return $"{Message} (at index {position})"; } } internal class ExpressionParser { private struct Token { public TokenId id; public string text; public int pos; } private enum TokenId { Unknown, End, Identifier, StringLiteral, IntegerLiteral, RealLiteral, Exclamation, Percent, Amphersand, OpenParen, CloseParen, Asterisk, Plus, Comma, Minus, Dot, Slash, Colon, LessThan, Equal, GreaterThan, Question, OpenBracket, CloseBracket, Bar, ExclamationEqual, DoubleAmphersand, LessThanEqual, LessGreater, DoubleEqual, GreaterThanEqual, DoubleBar } private interface ILogicalSignatures { void F(bool x, bool y); void F(bool? x, bool? y); } private interface IArithmeticSignatures { void F(int x, int y); void F(uint x, uint y); void F(long x, long y); void F(ulong x, ulong y); void F(float x, float y); void F(double x, double y); void F(decimal x, decimal y); void F(int? x, int? y); void F(uint? x, uint? y); void F(long? x, long? y); void F(ulong? x, ulong? y); void F(float? x, float? y); void F(double? x, double? y); void F(decimal? x, decimal? y); } private interface IRelationalSignatures : IArithmeticSignatures { void F(string x, string y); void F(char x, char y); void F(DateTime x, DateTime y); void F(TimeSpan x, TimeSpan y); void F(char? x, char? y); void F(DateTime? x, DateTime? y); void F(TimeSpan? x, TimeSpan? y); } private interface IEqualitySignatures : IRelationalSignatures, IArithmeticSignatures { void F(bool x, bool y); void F(bool? x, bool? y); } private interface IAddSignatures : IArithmeticSignatures { void F(DateTime x, TimeSpan y); void F(TimeSpan x, TimeSpan y); void F(DateTime? x, TimeSpan? y); void F(TimeSpan? x, TimeSpan? y); } private interface ISubtractSignatures : IAddSignatures, IArithmeticSignatures { void F(DateTime x, DateTime y); void F(DateTime? x, DateTime? y); } private interface INegationSignatures { void F(int x); void F(long x); void F(float x); void F(double x); void F(decimal x); void F(int? x); void F(long? x); void F(float? x); void F(double? x); void F(decimal? x); } private interface INotSignatures { void F(bool x); void F(bool? x); } private interface IEnumerableSignatures { void Where(bool predicate); void Any(); void Any(bool predicate); void All(bool predicate); void Count(); void Count(bool predicate); void Min(object selector); void Max(object selector); void Sum(int selector); void Sum(int? selector); void Sum(long selector); void Sum(long? selector); void Sum(float selector); void Sum(float? selector); void Sum(double selector); void Sum(double? selector); void Sum(decimal selector); void Sum(decimal? selector); void Average(int selector); void Average(int? selector); void Average(long selector); void Average(long? selector); void Average(float selector); void Average(float? selector); void Average(double selector); void Average(double? selector); void Average(decimal selector); void Average(decimal? selector); } private class MethodData { public MethodBase MethodBase; public ParameterInfo[] Parameters; public Expression[] Args; } private static readonly Type[] predefinedTypes = new Type[20] { typeof(object), typeof(bool), typeof(char), typeof(string), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Math), typeof(Convert) }; private static readonly Expression trueLiteral = Expression.Constant(true); private static readonly Expression falseLiteral = Expression.Constant(false); private static readonly Expression nullLiteral = Expression.Constant(null); private static readonly string keywordIt = "it"; private static readonly string keywordIif = "iif"; private static readonly string keywordNew = "new"; private static Dictionary<string, object> keywords; private Dictionary<string, object> symbols; private IDictionary<string, object> externals; private Dictionary<Expression, string> literals; private ParameterExpression it; private string text; private int textPos; private int textLen; private char ch; private Token token; public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values) { if (expression == null) { throw new ArgumentNullException("expression"); } if (keywords == null) { keywords = CreateKeywords(); } symbols = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); literals = new Dictionary<Expression, string>(); if (parameters != null) { ProcessParameters(parameters); } if (values != null) { ProcessValues(values); } text = expression; textLen = text.Length; SetTextPos(0); NextToken(); } private void ProcessParameters(ParameterExpression[] parameters) { foreach (ParameterExpression parameterExpression in parameters) { if (!string.IsNullOrEmpty(parameterExpression.Name)) { AddSymbol(parameterExpression.Name, parameterExpression); } } if (parameters.Length == 1 && string.IsNullOrEmpty(parameters[0].Name)) { it = parameters[0]; } } private void ProcessValues(object[] values) { for (int i = 0; i < values.Length; i++) { object obj = values[i]; if (i == values.Length - 1 && obj is IDictionary<string, object>) { externals = (IDictionary<string, object>)obj; } else { AddSymbol("@" + i.ToString(CultureInfo.InvariantCulture), obj); } } } private void AddSymbol(string name, object value) { if (symbols.ContainsKey(name)) { throw ParseError("The identifier '{0}' was defined more than once", name); } symbols.Add(name, value); } public Expression Parse(Type resultType) { int pos = token.pos; Expression expression = ParseExpression(); if ((object)resultType != null && (expression = PromoteExpression(expression, resultType, exact: true)) == null) { throw ParseError(pos, "Expression of type '{0}' expected", GetTypeName(resultType)); } ValidateToken(TokenId.End, "Syntax error"); return expression; } public IEnumerable<DynamicOrdering> ParseOrdering() { List<DynamicOrdering> list = new List<DynamicOrdering>(); while (true) { Expression selector = ParseExpression(); bool ascending = true; if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) { NextToken(); } else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) { NextToken(); ascending = false; } list.Add(new DynamicOrdering { Selector = selector, Ascending = ascending }); if (token.id != TokenId.Comma) { break; } NextToken(); } ValidateToken(TokenId.End, "Syntax error"); return list; } private Expression ParseExpression() { int pos = token.pos; Expression expression = ParseLogicalOr(); if (token.id == TokenId.Question) { NextToken(); Expression expr = ParseExpression(); ValidateToken(TokenId.Colon, "':' expected"); NextToken(); Expression expr2 = ParseExpression(); expression = GenerateConditional(expression, expr, expr2, pos); } return expression; } private Expression ParseLogicalOr() { Expression left = ParseLogicalAnd(); while (this.token.id == TokenId.DoubleBar || TokenIdentifierIs("or")) { Token token = this.token; NextToken(); Expression right = ParseLogicalAnd(); CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos); left = Expression.OrElse(left, right); } return left; } private Expression ParseLogicalAnd() { Expression left = ParseComparison(); while (this.token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and")) { Token token = this.token; NextToken(); Expression right = ParseComparison(); CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos); left = Expression.AndAlso(left, right); } return left; } private Expression ParseComparison() { Expression left = ParseAdditive(); while (this.token.id == TokenId.Equal || this.token.id == TokenId.DoubleEqual || this.token.id == TokenId.ExclamationEqual || this.token.id == TokenId.LessGreater || this.token.id == TokenId.GreaterThan || this.token.id == TokenId.GreaterThanEqual || this.token.id == TokenId.LessThan || this.token.id == TokenId.LessThanEqual) { Token token = this.token; NextToken(); Expression right = ParseAdditive(); bool flag = token.id == TokenId.Equal || token.id == TokenId.DoubleEqual || token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater; if (flag && !left.Type.IsValueType && !right.Type.IsValueType) { if ((object)left.Type != right.Type) { if (left.Type.IsAssignableFrom(right.Type)) { right = Expression.Convert(right, left.Type); } else { if (!right.Type.IsAssignableFrom(left.Type)) { throw IncompatibleOperandsError(token.text, left, right, token.pos); } left = Expression.Convert(left, right.Type); } } } else if (IsEnumType(left.Type) || IsEnumType(right.Type)) { if ((object)left.Type != right.Type) { Expression expression; if ((expression = PromoteExpression(right, left.Type, exact: true)) != null) { right = expression; } else { if ((expression = PromoteExpression(left, right.Type, exact: true)) == null) { throw IncompatibleOperandsError(token.text, left, right, token.pos); } left = expression; } } } else { CheckAndPromoteOperands(flag ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), token.text, ref left, ref right, token.pos); } switch (token.id) { case TokenId.Equal: case TokenId.DoubleEqual: left = GenerateEqual(left, right); break; case TokenId.ExclamationEqual: case TokenId.LessGreater: left = GenerateNotEqual(left, right); break; case TokenId.GreaterThan: left = GenerateGreaterThan(left, right); break; case TokenId.GreaterThanEqual: left = GenerateGreaterThanEqual(left, right); break; case TokenId.LessThan: left = GenerateLessThan(left, right); break; case TokenId.LessThanEqual: left = GenerateLessThanEqual(left, right); break; } } return left; } private Expression ParseAdditive() { Expression left = ParseMultiplicative(); while (this.token.id == TokenId.Plus || this.token.id == TokenId.Minus || this.token.id == TokenId.Amphersand) { Token token = this.token; NextToken(); Expression right = ParseMultiplicative(); TokenId id = token.id; if (id != TokenId.Amphersand) { if (id != TokenId.Plus) { if (id == TokenId.Minus) { CheckAndPromoteOperands(typeof(ISubtractSignatures), token.text, ref left, ref right, token.pos); left = GenerateSubtract(left, right); } continue; } if ((object)left.Type != typeof(string) && (object)right.Type != typeof(string)) { CheckAndPromoteOperands(typeof(IAddSignatures), token.text, ref left, ref right, token.pos); left = GenerateAdd(left, right); continue; } } left = GenerateStringConcat(left, right); } return left; } private Expression ParseMultiplicative() { Expression left = ParseUnary(); while (this.token.id == TokenId.Asterisk || this.token.id == TokenId.Slash || this.token.id == TokenId.Percent || TokenIdentifierIs("mod")) { Token token = this.token; NextToken(); Expression right = ParseUnary(); CheckAndPromoteOperands(typeof(IArithmeticSignatures), token.text, ref left, ref right, token.pos); switch (token.id) { case TokenId.Asterisk: left = Expression.Multiply(left, right); break; case TokenId.Slash: left = Expression.Divide(left, right); break; case TokenId.Identifier: case TokenId.Percent: left = Expression.Modulo(left, right); break; } } return left; } private Expression ParseUnary() { if (this.token.id == TokenId.Minus || this.token.id == TokenId.Exclamation || TokenIdentifierIs("not")) { Token token = this.token; NextToken(); if (token.id == TokenId.Minus && (this.token.id == TokenId.IntegerLiteral || this.token.id == TokenId.RealLiteral)) { this.token.text = "-" + this.token.text; this.token.pos = token.pos; return ParsePrimary(); } Expression expr = ParseUnary(); if (token.id == TokenId.Minus) { CheckAndPromoteOperand(typeof(INegationSignatures), token.text, ref expr, token.pos); return Expression.Negate(expr); } CheckAndPromoteOperand(typeof(INotSignatures), token.text, ref expr, token.pos); return Expression.Not(expr); } return ParsePrimary(); } private Expression ParsePrimary() { Expression expression = ParsePrimaryStart(); while (true) { if (token.id == TokenId.Dot) { NextToken(); expression = ParseMemberAccess(null, expression); continue; } if (token.id != TokenId.OpenBracket) { break; } expression = ParseElementAccess(expression); } return expression; } private Expression ParsePrimaryStart() { return token.id switch { TokenId.Identifier => ParseIdentifier(), TokenId.StringLiteral => ParseStringLiteral(), TokenId.IntegerLiteral => ParseIntegerLiteral(), TokenId.RealLiteral => ParseRealLiteral(), TokenId.OpenParen => ParseParenExpression(), _ => throw ParseError("Expression expected"), }; } private Expression ParseStringLiteral() { ValidateToken(TokenId.StringLiteral); char c = token.text[0]; string text = token.text.Substring(1, token.text.Length - 2); int startIndex = 0; while (true) { int num = text.IndexOf(c, startIndex); if (num < 0) { break; } text = text.Remove(num, 1); startIndex = num + 1; } if (c == '\'') { if (text.Length != 1) { throw ParseError("Character literal must contain exactly one character"); } NextToken(); return CreateLiteral(text[0], text); } NextToken(); return CreateLiteral(text, text); } private Expression ParseIntegerLiteral() { ValidateToken(TokenId.IntegerLiteral); string text = token.text; if (text[0] != '-') { if (!ulong.TryParse(text, out var result)) { throw ParseError("Invalid integer literal '{0}'", text); } NextToken(); if (result <= int.MaxValue) { return CreateLiteral((int)result, text); } if (result <= uint.MaxValue) { return CreateLiteral((uint)result, text); } if (result <= long.MaxValue) { return CreateLiteral((long)result, text); } return CreateLiteral(result, text); } if (!long.TryParse(text, out var result2)) { throw ParseError("Invalid integer literal '{0}'", text); } NextToken(); if (result2 >= int.MinValue && result2 <= int.MaxValue) { return CreateLiteral((int)result2, text); } return CreateLiteral(result2, text); } private Expression ParseRealLiteral() { ValidateToken(TokenId.RealLiteral); string text = token.text; object obj = null; char c = text[text.Length - 1]; double result2; if (c == 'F' || c == 'f') { if (float.TryParse(text.Substring(0, text.Length - 1), out var result)) { obj = result; } } else if (double.TryParse(text, out result2)) { obj = result2; } if (obj == null) { throw ParseError("Invalid real literal '{0}'", text); } NextToken(); return CreateLiteral(obj, text); } private Expression CreateLiteral(object value, string text) { ConstantExpression constantExpression = Expression.Constant(value); literals.Add(constantExpression, text); return constantExpression; } private Expression ParseParenExpression() { ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); Expression result = ParseExpression(); ValidateToken(TokenId.CloseParen, "')' or operator expected"); NextToken(); return result; } private Expression ParseIdentifier() { ValidateToken(TokenId.Identifier); if (keywords.TryGetValue(token.text, out var value)) { if (value is Type) { return ParseTypeAccess((Type)value); } if (value == keywordIt) { return ParseIt(); } if (value == keywordIif) { return ParseIif(); } if (value == keywordNew) { return ParseNew(); } NextToken(); return (Expression)value; } if (symbols.TryGetValue(token.text, out value) || (externals != null && externals.TryGetValue(token.text, out value))) { Expression expression = value as Expression; if (expression == null) { expression = Expression.Constant(value); } else if (expression is LambdaExpression lambda) { return ParseLambdaInvocation(lambda); } NextToken(); return expression; } if (it != null) { return ParseMemberAccess(null, it); } throw ParseError("Unknown identifier '{0}'", token.text); } private Expression ParseIt() { if (it == null) { throw ParseError("No 'it' is in scope"); } NextToken(); return it; } private Expression ParseIif() { int pos = token.pos; NextToken(); Expression[] array = ParseArgumentList(); if (array.Length != 3) { throw ParseError(pos, "The 'iif' function requires three arguments"); } return GenerateConditional(array[0], array[1], array[2], pos); } private Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) { if ((object)test.Type != typeof(bool)) { throw ParseError(errorPos, "The first expression must be of type 'Boolean'"); } if ((object)expr1.Type != expr2.Type) { Expression expression = ((expr2 != nullLiteral) ? PromoteExpression(expr1, expr2.Type, exact: true) : null); Expression expression2 = ((expr1 != nullLiteral) ? PromoteExpression(expr2, expr1.Type, exact: true) : null); if (expression != null && expression2 == null) { expr1 = expression; } else { if (expression2 == null || expression != null) { string text = ((expr1 != nullLiteral) ? expr1.Type.Name : "null"); string text2 = ((expr2 != nullLiteral) ? expr2.Type.Name : "null"); if (expression != null && expression2 != null) { throw ParseError(errorPos, "Both of the types '{0}' and '{1}' convert to the other", text, text2); } throw ParseError(errorPos, "Neither of the types '{0}' and '{1}' converts to the other", text, text2); } expr2 = expression2; } } return Expression.Condition(test, expr1, expr2); } private Expression ParseNew() { NextToken(); ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); List<DynamicProperty> list = new List<DynamicProperty>(); List<Expression> list2 = new List<Expression>(); while (true) { int pos = token.pos; Expression expression = ParseExpression(); string name; if (TokenIdentifierIs("as")) { NextToken(); name = GetIdentifier(); NextToken(); } else { if (!(expression is MemberExpression memberExpression)) { throw ParseError(pos, "Expression is missing an 'as' clause"); } name = memberExpression.Member.Name; } list2.Add(expression); list.Add(new DynamicProperty(name, expression.Type)); if (token.id != TokenId.Comma) { break; } NextToken(); } ValidateToken(TokenId.CloseParen, "')' or ',' expected"); NextToken(); Type type = DynamicExpression.CreateClass(list); MemberBinding[] array = new MemberBinding[list.Count]; for (int i = 0; i < array.Length; i++) { array[i] = Expression.Bind(type.GetProperty(list[i].Name), list2[i]); } return Expression.MemberInit(Expression.New(type), array); } private Expression ParseLambdaInvocation(LambdaExpression lambda) { int pos = token.pos; NextToken(); Expression[] array = ParseArgumentList(); if (FindMethod(lambda.Type, "Invoke", staticAccess: false, array, out var _) != 1) { throw ParseError(pos, "Argument list incompatible with lambda expression"); } return Expression.Invoke(lambda, array); } private Expression ParseTypeAccess(Type type) { int pos = token.pos; NextToken(); if (token.id == TokenId.Question) { if (!type.IsValueType || IsNullableType(type)) { throw ParseError(pos, "Type '{0}' has no nullable form", GetTypeName(type)); } type = typeof(Nullable<>).MakeGenericType(type); NextToken(); } if (token.id == TokenId.OpenParen) { Expression[] array = ParseArgumentList(); MethodBase method; switch (FindBestMethod(type.GetConstructors(), array, out method)) { case 0: if (array.Length == 1) { return GenerateConversion(array[0], type, pos); } throw ParseError(pos, "No matching constructor in type '{0}'", GetTypeName(type)); case 1: return Expression.New((ConstructorInfo)method, array); default: throw ParseError(pos, "Ambiguous invocation of '{0}' constructor", GetTypeName(type)); } } ValidateToken(TokenId.Dot, "'.' or '(' expected"); NextToken(); return ParseMemberAccess(type, null); } private Expression GenerateConversion(Expression expr, Type type, int errorPos) { Type type2 = expr.Type; if ((object)type2 == type) { return expr; } if (type2.IsValueType && type.IsValueType) { if ((IsNullableType(type2) || IsNullableType(type)) && (object)GetNonNullableType(type2) == GetNonNullableType(type)) { return Expression.Convert(expr, type); } if (((IsNumericType(type2) || IsEnumType(type2)) && IsNumericType(type)) || IsEnumType(type)) { return Expression.ConvertChecked(expr, type); } } if (type2.IsAssignableFrom(type) || type.IsAssignableFrom(type2) || type2.IsInterface || type.IsInterface) { return Expression.Convert(expr, type); } throw ParseError(errorPos, "A value of type '{0}' cannot be converted to type '{1}'", GetTypeName(type2), GetTypeName(type)); } private Expression ParseMemberAccess(Type type, Expression instance) { if (instance != null) { type = instance.Type; } int pos = token.pos; string identifier = GetIdentifier(); NextToken(); if (token.id == TokenId.OpenParen) { if (instance != null && (object)type != typeof(string)) { Type type2 = FindGenericType(typeof(IEnumerable<>), type); if ((object)type2 != null) { Type elementType = type2.GetGenericArguments()[0]; return ParseAggregate(instance, elementType, identifier, pos); } } Expression[] array = ParseArgumentList(); MethodBase method; switch (FindMethod(type, identifier, instance == null, array, out method)) { case 0: throw ParseError(pos, "No applicable method '{0}' exists in type '{1}'", identifier, GetTypeName(type)); case 1: { MethodInfo methodInfo = (MethodInfo)method; if (!IsPredefinedType(methodInfo.DeclaringType)) { throw ParseError(pos, "Methods on type '{0}' are not accessible", GetTypeName(methodInfo.DeclaringType)); } if ((object)methodInfo.ReturnType == typeof(void)) { throw ParseError(pos, "Method '{0}' in type '{1}' does not return a value", identifier, GetTypeName(methodInfo.DeclaringType)); } return Expression.Call(instance, methodInfo, array); } default: throw ParseError(pos, "Ambiguous invocation of method '{0}' in type '{1}'", identifier, GetTypeName(type)); } } MemberInfo memberInfo = FindPropertyOrField(type, identifier, instance == null); if ((object)memberInfo == null) { throw ParseError(pos, "No property or field '{0}' exists in type '{1}'", identifier, GetTypeName(type)); } if (!(memberInfo is PropertyInfo)) { return Expression.Field(instance, (FieldInfo)memberInfo); } return Expression.Property(instance, (PropertyInfo)memberInfo); } private static Type FindGenericType(Type generic, Type type) { while ((object)type != null && (object)type != typeof(object)) { if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == generic) { return type; } if (generic.IsInterface) { Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { Type type3 = FindGenericType(generic, type2); if ((object)type3 != null) { return type3; } } } type = type.BaseType; } return null; } private Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos) { ParameterExpression parameterExpression = it; ParameterExpression parameterExpression2 = (it = Expression.Parameter(elementType, "")); Expression[] array = ParseArgumentList(); it = parameterExpression; if (FindMethod(typeof(IEnumerableSignatures), methodName, staticAccess: false, array, out var method) != 1) { throw ParseError(errorPos, "No applicable aggregate method '{0}' exists", methodName); } return Expression.Call(typeArguments: (!(method.Name == "Min") && !(method.Name == "Max")) ? new Type[1] { elementType } : new Type[2] { elementType, array[0].Type }, arguments: (array.Length != 0) ? new Expression[2] { instance, Expression.Lambda(array[0], parameterExpression2) } : new Expression[1] { instance }, type: typeof(Enumerable), methodName: method.Name); } private Expression[] ParseArgumentList() { ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); Expression[] result = ((token.id != TokenId.CloseParen) ? ParseArguments() : new Expression[0]); ValidateToken(TokenId.CloseParen, "')' or ',' expected"); NextToken(); return result; } private Expression[] ParseArguments() { List<Expression> list = new List<Expression>(); while (true) { list.Add(ParseExpression()); if (token.id != TokenId.Comma) { break; } NextToken(); } return list.ToArray(); } private Expression ParseElementAccess(Expression expr) { int pos = token.pos; ValidateToken(TokenId.OpenBracket, "'(' expected"); NextToken(); Expression[] array = ParseArguments(); ValidateToken(TokenId.CloseBracket, "']' or ',' expected"); NextToken(); if (expr.Type.IsArray) { if (expr.Type.GetArrayRank() != 1 || array.Length != 1) { throw ParseError(pos, "Indexing of multi-dimensional arrays is not supported"); } Expression expression = PromoteExpression(array[0], typeof(int), exact: true); if (expression == null) { throw ParseError(pos, "Array index must be an integer expression"); } return Expression.ArrayIndex(expr, expression); } MethodBase method; return FindIndexer(expr.Type, array, out method) switch { 0 => throw ParseError(pos, "No applicable indexer exists in type '{0}'", GetTypeName(expr.Type)), 1 => Expression.Call(expr, (MethodInfo)method, array), _ => throw ParseError(pos, "Ambiguous invocation of indexer in type '{0}'", GetTypeName(expr.Type)), }; } private static bool IsPredefinedType(Type type) { Type[] array = predefinedTypes; for (int i = 0; i < array.Length; i++) { if ((object)array[i] == type) { return true; } } return false; } private static bool IsNullableType(Type type) { if (type.IsGenericType) { return (object)type.GetGenericTypeDefinition() == typeof(Nullable<>); } return false; } private static Type GetNonNullableType(Type type) { if (!IsNullableType(type)) { return type; } return type.GetGenericArguments()[0]; } private static string GetTypeName(Type type) { Type nonNullableType = GetNonNullableType(type); string text = nonNullableType.Name; if ((object)type != nonNullableType) { text += "?"; } return text; } private static bool IsNumericType(Type type) { return GetNumericTypeKind(type) != 0; } private static bool IsSignedIntegralType(Type type) { return GetNumericTypeKind(type) == 2; } private static bool IsUnsignedIntegralType(Type type) { return GetNumericTypeKind(type) == 3; } private static int GetNumericTypeKind(Type type) { type = GetNonNullableType(type); if (type.IsEnum) { return 0; } switch (Type.GetTypeCode(type)) { case TypeCode.Char: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return 1; case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return 2; case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return 3; default: return 0; } } private static bool IsEnumType(Type type) { return GetNonNullableType(type).IsEnum; } private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) { Expression[] array = new Expression[1] { expr }; if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1) { throw ParseError(errorPos, "Operator '{0}' incompatible with operand type '{1}'", opName, GetTypeName(array[0].Type)); } expr = array[0]; } private void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos) { Expression[] array = new Expression[2] { left, right }; if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1) { throw IncompatibleOperandsError(opName, left, right, errorPos); } left = array[0]; right = array[1]; } private Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos) { return ParseError(pos, "Operator '{0}' incompatible with operand types '{1}' and '{2}'", opName, GetTypeName(left.Type), GetTypeName(right.Type)); } private MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) { BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] array = item.FindMembers(MemberTypes.Field | MemberTypes.Property, bindingAttr, Type.FilterNameIgnoreCase, memberName); if (array.Length != 0) { return array[0]; } } return null; } private int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method) { BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] source = item.FindMembers(MemberTypes.Method, bindingAttr, Type.FilterNameIgnoreCase, methodName); int num = FindBestMethod(source.Cast<MethodBase>(), args, out method); if (num != 0) { return num; } } method = null; return 0; } private int FindIndexer(Type type, Expression[] args, out MethodBase method) { foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] defaultMembers = item.GetDefaultMembers(); if (defaultMembers.Length != 0) { IEnumerable<MethodBase> methods = from m in defaultMembers.OfType<PropertyInfo>().Select((Func<PropertyInfo, MethodBase>)((PropertyInfo p) => p.GetGetMethod())) where (object)m != null select m; int num = FindBestMethod(methods, args, out method); if (num != 0) { return num; } } } method = null; return 0; } private static IEnumerable<Type> SelfAndBaseTypes(Type type) { if (type.IsInterface) { List<Type> list = new List<Type>(); AddInterface(list, type); return list; } return SelfAndBaseClasses(type); } private static IEnumerable<Type> SelfAndBaseClasses(Type type) { while ((object)type != null) { yield return type; type = type.BaseType; } } private static void AddInterface(List<Type> types, Type type) { if (!types.Contains(type)) { types.Add(type); Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { AddInterface(types, type2); } } } private int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, out MethodBase method) { MethodData[] applicable = (from m in methods select new MethodData { MethodBase = m, Parameters = m.GetParameters() } into m where IsApplicable(m, args) select m).ToArray(); if (applicable.Length > 1) { applicable = applicable.Where((MethodData m) => applicable.All((MethodData n) => m == n || IsBetterThan(args, m, n))).ToArray(); } if (applicable.Length == 1) { MethodData methodData = applicable[0]; for (int i = 0; i < args.Length; i++) { args[i] = methodData.Args[i]; } method = methodData.MethodBase; } else { method = null; } return applicable.Length; } private bool IsApplicable(MethodData method, Expression[] args) { if (method.Parameters.Length != args.Length) { return false; } Expression[] array = new Expression[args.Length]; for (int i = 0; i < args.Length; i++) { ParameterInfo parameterInfo = method.Parameters[i]; if (parameterInfo.IsOut) { return false; } Expression expression = PromoteExpression(args[i], parameterInfo.ParameterType, exact: false); if (expression == null) { return false; } array[i] = expression; } method.Args = array; return true; } private Expression PromoteExpression(Expression expr, Type type, bool exact) { if ((object)expr.Type == type) { return expr; } if (expr is ConstantExpression) { ConstantExpression constantExpression = (ConstantExpression)expr; string value; if (constantExpression == nullLiteral) { if (!type.IsValueType || IsNullableType(type)) { return Expression.Constant(null, type); } } else if (literals.TryGetValue(constantExpression, out value)) { Type nonNullableType = GetNonNullableType(type); object obj = null; switch (Type.GetTypeCode(constantExpression.Type)) { case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: obj = ParseNumber(value, nonNullableType); break; case TypeCode.Double: if ((object)nonNullableType == typeof(decimal)) { obj = ParseNumber(value, nonNullableType); } break; case TypeCode.String: obj = ParseEnum(value, nonNullableType); break; } if (obj != null) { return Expression.Constant(obj, type); } } } if (IsCompatibleWith(expr.Type, type)) { if (type.IsValueType || exact) { return Expression.Convert(expr, type); } return expr; } return null; } private static object ParseNumber(string text, Type type) { switch (Type.GetTypeCode(GetNonNullableType(type))) { case TypeCode.SByte: { if (sbyte.TryParse(text, out var result6)) { return result6; } break; } case TypeCode.Byte: { if (byte.TryParse(text, out var result10)) { return result10; } break; } case TypeCode.Int16: { if (short.TryParse(text, out var result2)) { return result2; } break; } case TypeCode.UInt16: { if (ushort.TryParse(text, out var result8)) { return result8; } break; } case TypeCode.Int32: { if (int.TryParse(text, out var result4)) { return result4; } break; } case TypeCode.UInt32: { if (uint.TryParse(text, out var result11)) { return result11; } break; } case TypeCode.Int64: { if (long.TryParse(text, out var result9)) { return result9; } break; } case TypeCode.UInt64: { if (ulong.TryParse(text, out var result7)) { return result7; } break; } case TypeCode.Single: { if (float.TryParse(text, out var result5)) { return result5; } break; } case TypeCode.Double: { if (double.TryParse(text, out var result3)) { return result3; } break; } case TypeCode.Decimal: { if (decimal.TryParse(text, out var result)) { return result; } break; } } return null; } private static object ParseEnum(string name, Type type) { if (type.IsEnum) { MemberInfo[] array = type.FindMembers(MemberTypes.Field, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, Type.FilterNameIgnoreCase, name); if (array.Length != 0) { return ((FieldInfo)array[0]).GetValue(null); } } return null; } private static bool IsCompatibleWith(Type source, Type target) { if ((object)source == target) { return true; } if (!target.IsValueType) { return target.IsAssignableFrom(source); } Type nonNullableType = GetNonNullableType(source); Type nonNullableType2 = GetNonNullableType(target); if ((object)nonNullableType != source && (object)nonNullableType2 == target) { return false; } TypeCode typeCode = (nonNullableType.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType)); TypeCode typeCode2 = (nonNullableType2.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType2)); switch (typeCode) { case TypeCode.SByte: switch (typeCode2) { case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Byte: if ((uint)(typeCode2 - 6) <= 9u) { return true; } break; case TypeCode.Int16: switch (typeCode2) { case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt16: if ((uint)(typeCode2 - 8) <= 7u) { return true; } break; case TypeCode.Int32: switch (typeCode2) { case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt32: if ((uint)(typeCode2 - 10) <= 5u) { return true; } break; case TypeCode.Int64: if (typeCode2 == TypeCode.Int64 || (uint)(typeCode2 - 13) <= 2u) { return true; } break; case TypeCode.UInt64: if ((uint)(typeCode2 - 12) <= 3u) { return true; } break; case TypeCode.Single: if ((uint)(typeCode2 - 13) <= 1u) { return true; } break; default: if ((object)nonNullableType == nonNullableType2) { return true; } break; } return false; } private static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2) { bool result = false; for (int i = 0; i < args.Length; i++) { int num = CompareConversions(args[i].Type, m1.Parameters[i].ParameterType, m2.Parameters[i].ParameterType); if (num < 0) { return false; } if (num > 0) { result = true; } } return result; } private static int CompareConversions(Type s, Type t1, Type t2) { if ((object)t1 == t2) { return 0; } if ((object)s == t1) { return 1; } if ((object)s == t2) { return -1; } bool flag = IsCompatibleWith(t1, t2); bool flag2 = IsCompatibleWith(t2, t1); if (flag && !flag2) { return 1; } if (flag2 && !flag) { return -1; } if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) { return 1; } if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) { return -1; } return 0; } private Expression GenerateEqual(Expression left, Expression right) { return Expression.Equal(left, right); } private Expression GenerateNotEqual(Expression left, Expression right) { return Expression.NotEqual(left, right); } private Expression GenerateGreaterThan(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.GreaterThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.GreaterThan(left, right); } private Expression GenerateGreaterThanEqual(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.GreaterThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.GreaterThanOrEqual(left, right); } private Expression GenerateLessThan(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.LessThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.LessThan(left, right); } private Expression GenerateLessThanEqual(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.LessThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.LessThanOrEqual(left, right); } private Expression GenerateAdd(Expression left, Expression right) { if ((object)left.Type == typeof(string) && (object)right.Type == typeof(string)) { return GenerateStaticMethodCall("Concat", left, right); } return Expression.Add(left, right); } private Expression GenerateSubtract(Expression left, Expression right) { return Expression.Subtract(left, right); } private Expression GenerateStringConcat(Expression left, Expression right) { return Expression.Call(null, typeof(string).GetMethod("Concat", new Type[2] { typeof(object), typeof(object) }), new Expression[2] { left, right }); } private MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) { return left.Type.GetMethod(methodName, new Type[2] { left.Type, right.Type }); } private Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) { return Expression.Call(null, GetStaticMethod(methodName, left, right), new Expression[2] { left, right }); } private void SetTextPos(int pos) { textPos = pos; ch = ((textPos < textLen) ? text[textPos] : '\0'); } private void NextChar() { if (textPos < textLen) { textPos++; } ch = ((textPos < textLen) ? text[textPos] : '\0'); } private void NextToken() { while (char.IsWhiteSpace(ch)) { NextChar(); } int num = textPos; TokenId id; switch (ch) { case '!': NextChar(); if (ch == '=') { NextChar(); id = TokenId.ExclamationEqual; } else { id = TokenId.Exclamation; } break; case '%': NextChar(); id = TokenId.Percent; break; case '&': NextChar(); if (ch == '&') { NextChar(); id = TokenId.DoubleAmphersand; } else { id = TokenId.Amphersand; } break; case '(': NextChar(); id = TokenId.OpenParen; break; case ')': NextChar(); id = TokenId.CloseParen; break; case '*': NextChar(); id = TokenId.Asterisk; break; case '+': NextChar(); id = TokenId.Plus; break; case ',': NextChar(); id = TokenId.Comma; break; case '-': NextChar(); id = TokenId.Minus; break; case '.': NextChar(); id = TokenId.Dot; break; case '/': NextChar(); id = TokenId.Slash; break; case ':': NextChar(); id = TokenId.Colon; break; case '<': NextChar(); if (ch == '=') { NextChar(); id = TokenId.LessThanEqual; } else if (ch == '>') { NextChar(); id = TokenId.LessGreater; } else { id = TokenId.LessThan; } break; case '=': NextChar(); if (ch == '=') { NextChar(); id = TokenId.DoubleEqual; } else { id = TokenId.Equal; } break; case '>': NextChar(); if (ch == '=') { NextChar(); id = TokenId.GreaterThanEqual; } else { id = TokenId.GreaterThan; } break; case '?': NextChar(); id = TokenId.Question; break; case '[': NextChar(); id = TokenId.OpenBracket; break; case ']': NextChar(); id = TokenId.CloseBracket; break; case '|': NextChar(); if (ch == '|') { NextChar(); id = TokenId.DoubleBar; } else { id = TokenId.Bar; } break; case '"': case '\'': { char c = ch; do { NextChar(); while (textPos < textLen && ch != c) { NextChar(); } if (textPos == textLen) { throw ParseError(textPos, "Unterminated string literal"); } NextChar(); } while (ch == c); id = TokenId.StringLiteral; break; } default: if (char.IsLetter(ch) || ch == '@' || ch == '_') { do { NextChar(); } while (char.IsLetterOrDigit(ch) || ch == '_'); id = TokenId.Identifier; } else if (char.IsDigit(ch)) { id = TokenId.IntegerLiteral; do { NextChar(); } while (char.IsDigit(ch)); if (ch == '.') { id = TokenId.RealLiteral; NextChar(); ValidateDigit(); do { NextChar(); } while (char.IsDigit(ch)); } if (ch == 'E' || ch == 'e') { id = TokenId.RealLiteral; NextChar(); if (ch == '+' || ch == '-') { NextChar(); } ValidateDigit(); do { NextChar(); } while (char.IsDigit(ch)); } if (ch == 'F' || ch == 'f') { NextChar(); } } else { if (textPos != textLen) { throw ParseError(textPos, "Syntax error '{0}'", ch); } id = TokenId.End; } break; } token.id = id; token.text = text.Substring(num, textPos - num); token.pos = num; } private bool TokenIdentifierIs(string id) { if (token.id == TokenId.Identifier) { return string.Equals(id, token.text, StringComparison.OrdinalIgnoreCase); } return false; } private string GetIdentifier() { ValidateToken(TokenId.Identifier, "Identifier expected"); string text = token.text; if (text.Length > 1 && text[0] == '@') { text = text.Substring(1); } return text; } private void ValidateDigit() { if (!char.IsDigit(ch)) { throw ParseError(textPos, "Digit expected"); } } private void ValidateToken(TokenId t, string errorMessage) { if (token.id != t) { throw ParseError(errorMessage); } } private void ValidateToken(TokenId t) { if (token.id != t) { throw ParseError("Syntax error"); } } private Exception ParseError(string format, params object[] args) { return ParseError(token.pos, format, args); } private Exception ParseError(int pos, string format, params object[] args) { return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); } private static Dictionary<string, object> CreateKeywords() { Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); dictionary.Add("true", trueLiteral); dictionary.Add("false", falseLiteral); dictionary.Add("null", nullLiteral); dictionary.Add(keywordIt, keywordIt); dictionary.Add(keywordIif, keywordIif); dictionary.Add(keywordNew, keywordNew); Type[] array = predefinedTypes; foreach (Type type in array) { dictionary.Add(type.Name, type); } return dictionary; } } internal static class Res { public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once"; public const string ExpressionTypeMismatch = "Expression of type '{0}' expected"; public const string ExpressionExpected = "Expression expected"; public const string InvalidCharacterLiteral = "Character literal must contain exactly one character"; public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'"; public const string InvalidRealLiteral = "Invalid real literal '{0}'"; public const string UnknownIdentifier = "Unknown identifier '{0}'"; public const string NoItInScope = "No 'it' is in scope"; public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments"; public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'"; public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other"; public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other"; public const string MissingAsClause = "Expression is missing an 'as' clause"; public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression"; public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form"; public const string NoMatchingConstructor = "No matching constructor in type '{0}'"; public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor"; public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'"; public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'"; public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible"; public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value"; public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'"; public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'"; public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists"; public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported"; public const string InvalidIndex = "Array index must be an integer expression"; public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'"; public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'"; public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'"; public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'"; public const string UnterminatedStringLiteral = "Unterminated string literal"; public const string InvalidCharacter = "Syntax error '{0}'"; public const string DigitExpected = "Digit expected"; public const string SyntaxError = "Syntax error"; public const string TokenExpected = "{0} expected"; public const string ParseExceptionFormat = "{0} (at index {1})"; public const string ColonExpected = "':' expected"; public const string OpenParenExpected = "'(' expected"; public const string CloseParenOrOperatorExpected = "')' or operator expected"; public const string CloseParenOrCommaExpected = "')' or ',' expected"; public const string DotOrOpenParenExpected = "'.' or '(' expected"; public const string OpenBracketExpected = "'[' expected"; public const string CloseBracketOrCommaExpected = "']' or ',' expected"; public const string IdentifierExpected = "Identifier expected"; } } namespace SimpleJSON { public enum JSONNodeType { Array = 1, Object = 2, String = 3, Number = 4, NullValue = 5, Boolean = 6, None = 7, Custom = 255 } public enum JSONTextMode { Compact, Indent } public abstract class JSONNode { public struct Enumerator { private enum Type { None, Array, Object } private Type type; private Dictionary<string, JSONNode>.Enumerator m_Object; private List<JSONNode>.Enumerator m_Array; public bool IsValid => type != Type.None; public KeyValuePair<string, JSONNode> Current { get { if (type == Type.Array) { return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current); } if (type == Type.Object) { return m_Object.Current; } return new KeyValuePair<string, JSONNode>(string.Empty, null); } } public Enumerator(List<JSONNode>.Enumerator aArrayEnum) { type = Type.Array; m_Object = default(Dictionary<string, JSONNode>.Enumerator); m_Array = aArrayEnum; } public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) { type = Type.Object; m_Object = aDictEnum; m_Array = default(List<JSONNode>.Enumerator); } public bool MoveNext() { if (type == Type.Array) { return m_Array.MoveNext(); } if (type == Type.Object) { return m_Object.MoveNext(); } return false; } } public struct ValueEnumerator { private Enumerator m_Enumerator; public JSONNode Current => m_Enumerator.Current.Value; public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public bool MoveNext() { return m_Enumerator.MoveNext(); } public ValueEnumerator GetEnumerator() { return this; } } public struct KeyEnumerator { private Enumerator m_Enumerator; public JSONNode Current => m_Enumerator.Current.Key; public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public bool MoveNext() { return m_Enumerator.MoveNext(); } public KeyEnumerator GetEnumerator() { return this; } } public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IDisposable, IEnumerator, IEnumerable<KeyValuePair<string, JSONNode>>, IEnumerable { private JSONNode m_Node; private Enumerator m_Enumerator; public KeyValuePair<string, JSONNode> Current => m_Enumerator.Current; object IEnumerator.Current => m_Enumerator.Current; internal LinqEnumerator(JSONNode aNode) { m_Node = aNode; if (m_Node != null) { m_Enumerator = m_Node.GetEnumerator(); } } public bool MoveNext() { return m_Enumerator.MoveNext(); } public void Dispose() { m_Node = null; m_Enumerator = default(Enumerator); } public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator() { return new LinqEnumerator(m_Node); } public void Reset() { if (m_Node != null) { m_Enumerator = m_Node.GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() { return new LinqEnumerator(m_Node); } } public static bool forceASCII; [ThreadStatic] private static StringBuilder m_EscapeBuilder; public abstract JSONNodeType Tag { get; } public virtual JSONNode this[int aIndex] { get { return null; } set { } } public virtual JSONNode this[string aKey] { get { return null; } set { } } public virtual string Value { get { return ""; } set { } } public virtual int Count => 0; public virtual bool IsNumber => false; public virtual bool IsString => false; public virtual bool IsBoolean => false; public virtual bool IsNull => false; public virtual bool IsArray => false; public virtual bool IsObject => false; public virtual bool Inline { get { return false; } set { } } public virtual IEnumerable<JSONNode> Children { get { yield break; } } public IEnumerable<JSONNode> DeepChildren { get { foreach (JSONNode child in Children) { foreach (JSONNode deepChild in child.DeepChildren) { yield return deepChild; } } } } public IEnumerable<KeyValuePair<string, JSONNode>> Linq => new LinqEnumerator(this); public KeyEnumerator Keys => new KeyEnumerator(GetEnumerator()); public ValueEnumerator Values => new ValueEnumerator(GetEnumerator()); public virtual double AsDouble { get { double result = 0.0; if (double.TryParse(Value, out result)) { return result; } return 0.0; } set { Value = value.ToString(); } } public virtual int AsInt { get { return (int)AsDouble; } set { AsDouble = value; } } public virtual float AsFloat { get { return (float)AsDouble; } set { AsDouble = value; } } public virtual bool AsBool { get { bool result = false; if (bool.TryParse(Value, out result)) { return result; } return !string.IsNullOrEmpty(Value); } set { Value = (value ? "true" : "false"); } } public virtual JSONArray AsArray => this as JSONArray; public virtual JSONObject AsObject => this as JSONObject; internal static StringBuilder EscapeBuilder { get { if (m_EscapeBuilder == null) { m_EscapeBuilder = new StringBuilder(); } return m_EscapeBuilder; } } public virtual void Add(string aKey, JSONNode aItem) { } public virtual void Add(JSONNode aItem) { Add("", aItem); } public virtual JSONNode Remove(string aKey) { return null; } public virtual JSONNode Remove(int aIndex) { return null; } public virtual JSONNode Remove(JSONNode aNode) { return aNode; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); WriteToStringBuilder(stringBuilder, 0, 0, JSONTextMode.Compact); return stringBuilder.ToString(); } public virtual string ToString(int aIndent) { StringBuilder stringBuilder = new StringBuilder(); WriteToStringBuilder(stringBuilder, 0, aIndent, JSONTextMode.Indent); return stringBuilder.ToString(); } internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode); public abstract Enumerator GetEnumerator(); public static implicit operator JSONNode(string s) { return new JSONString(s); } public static implicit operator string(JSONNode d) { if (!(d == null)) { return d.Value; } return null; } public static implicit operator JSONNode(double n) { return new JSONNumber(n); } public static implicit operator double(JSONNode d) { if (!(d == null)) { return d.AsDouble; } return 0.0; } public static implicit operator JSONNode(float n) { return new JSONNumber(n); } public static implicit operator float(JSONNode d) { if (!(d == null)) { return d.AsFloat; } return 0f; } public static implicit operator JSONNode(int n) { return new JSONNumber(n); } public static implicit operator int(JSONNode d) { if (!(d == null)) { return d.AsInt; } return 0; } public static implicit operator JSONNode(bool b) { return new JSONBool(b); } public static implicit operator bool(JSONNode d) { if (!(d == null)) { return d.AsBool; } return false; } public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue) { return aKeyValue.Value; } public static bool operator ==(JSONNode a, object b) { if ((object)a == b) { return true; } bool flag = a is JSONNull || (object)a == null || a is JSONLazyCreator; bool flag2 = b is JSONNull || b == null || b is JSONLazyCreator; if (flag && flag2) { return true; } if (!flag) { return a.Equals(b); } return false; } public static bool operator !=(JSONNode a, object b) { return !(a == b); } public override bool Equals(object obj) { return (object)this == obj; } public override int GetHashCode() { return base.GetHashCode(); } internal static string Escape(string aText) { StringBuilder escapeBuilder = EscapeBuilder; escapeBuilder.Length = 0; if (escapeBuilder.Capacity < aText.Length + aText.Length / 10) { escapeBuilder.Capacity = aText.Length + aText.Length / 10; } foreach (char c in aText) { switch (c) { case '\\': escapeBuilder.Append("\\\\"); continue; case '"': escapeBuilder.Append("\\\""); continue; case '\n': escapeBuilder.Append("\\n"); continue; case '\r': escapeBuilder.Append("\\r"); continue; case '\t': escapeBuilder.Append("\\t"); continue; case '\b': escapeBuilder.Append("\\b"); continue; case '\f': escapeBuilder.Append("\\f"); continue; } if (c < ' ' || (forceASCII && c > '\u007f')) { ushort num = c; escapeBuilder.Append("\\u").Append(num.ToString("X4")); } else { escapeBuilder.Append(c); } } string result = escapeBuilder.ToString(); escapeBuilder.Length = 0; return result; } private static void ParseElement(JSONNode ctx, string token, string tokenName, bool quoted) { if (quoted) { ctx.Add(tokenName, token); return; } string text = token.ToLower(); switch (text) { case "false": case "true": ctx.Add(tokenName, text == "true"); return; case "null": ctx.Add(tokenName, null); return; } if (double.TryParse(token, out var result)) { ctx.Add(tokenName, result); } else { ctx.Add(tokenName, token); } } public static JSONNode Parse(string aJSON) { Stack<JSONNode> stack = new Stack<JSONNode>(); JSONNode jSONNode = null; int i = 0; StringBuilder stringBuilder = new StringBuilder(); string text = ""; bool flag = false; bool flag2 = false; for (; i < aJSON.Length; i++) { switch (aJSON[i]) { case '{': if (flag) { stringBuilder.Append(aJSON[i]); break; } stack.Push(new JSONObject()); if (jSONNode != null) { jSONNode.Add(text, stack.Peek()); } text = ""; stringBuilder.Length = 0; jSONNode = stack.Peek(); break; case '[': if (flag) { stringBuilder.Append(aJSON[i]); break; } stack.Push(new JSONArray()); if (jSONNode != null) { jSONNode.Add(text, stack.Peek()); } text = ""; stringBuilder.Length = 0; jSONNode = stack.Peek(); break; case ']': case '}': if (flag) { stringBuilder.Append(aJSON[i]); break; } if (stack.Count == 0) { throw new Exception("JSON Parse: Too many closing brackets"); } stack.Pop(); if (stringBuilder.Length > 0 || flag2) { ParseElement(jSONNode, stringBuilder.ToString(), text, flag2); flag2 = false; } text = ""; stringBuilder.Length = 0; if (stack.Count > 0) { jSONNode = stack.Peek(); } break; case ':': if (flag) { stringBuilder.Append(aJSON[i]); break; } text = stringBuilder.ToString(); stringBuilder.Length = 0; flag2 = false; break; case '"': flag = !flag; flag2 = flag2 || flag; break; case ',': if (flag) { stringBuilder.Append(aJSON[i]); break; } if (stringBuilder.Length > 0 || flag2) { ParseElement(jSONNode, stringBuilder.ToString(), text, flag2); flag2 = false; } text = ""; stringBuilder.Length = 0; flag2 = false; break; case '\t': case ' ': if (flag) { stringBuilder.Append(aJSON[i]); } break; case '\\': i++; if (flag) { char c = aJSON[i]; switch (c) { case 't': stringBuilder.Append('\t'); break; case 'r': stringBuilder.Append('\r'); break; case 'n': stringBuilder.Append('\n'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'u': { string s = aJSON.Substring(i + 1, 4); stringBuilder.Append((char)int.Parse(s, NumberStyles.AllowHexSpecifier)); i += 4; break; } default: stringBuilder.Append(c); break; } } break; default: stringBuilder.Append(aJSON[i]); break; case '\n': case '\r': break; } } if (flag) { throw new Exception("JSON Parse: Quotation marks seems to be messed up."); } return jSONNode; } } public class JSONArray : JSONNode { private List<JSONNode> m_List = new List<JSONNode>(); private bool inline; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag => JSONNodeType.Array; public override bool IsArray => true; public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_List.Count) { return new JSONLazyCreator(this); } return m_List[aIndex]; } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (aIndex < 0 || aIndex >= m_List.Count) { m_List.Add(value); } else { m_List[aIndex] = value; } } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this); } set { if (value == null) { value = JSONNull.CreateOrGet(); } m_List.Add(value); } } public override int Count => m_List.Count; public override IEnumerable<JSONNode> Children { get { foreach (JSONNode item in m_List) { yield return item; } } } public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) { aItem = JSONNull.CreateOrGet(); } m_List.Add(aItem); } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_List.Count) { return null; } JSONNode result = m_List[aIndex]; m_List.RemoveAt(aIndex); return result; } public override JSONNode Remove(JSONNode aNode) { m_List.Remove(aNode); return aNode; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('['); int count = m_List.Count; if (inline) { aMode = JSONTextMode.Compact; } for (int i = 0; i < count; i++) { if (i > 0) { aSB.Append(','); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine(); } if (aMode == JSONTextMode.Indent) { aSB.Append(' ', aIndent + aIndentInc); } m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine().Append(' ', aIndent); } aSB.Append(']'); } } public class JSONObject : JSONNode { private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>(); private bool inline; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag => JSONNodeType.Object; public override bool IsObject => true; public override JSONNode this[string aKey] { get { if (m_Dict.ContainsKey(aKey)) { return m_Dict[aKey]; } return new JSONLazyCreator(this, aKey); } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (m_Dict.ContainsKey(aKey)) { m_Dict[aKey] = value; } else { m_Dict.Add(aKey, value); } } } public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_Dict.Count) { return null; } return m_Dict.ElementAt(aIndex).Value; } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (aIndex >= 0 && aIndex < m_Dict.Count) { string key = m_Dict.ElementAt(aIndex).Key; m_Dict[key] = value; } } } public override int Count => m_Dict.Count; public override IEnumerable<JSONNode> Children { get { foreach (KeyValuePair<string, JSONNode> item in m_Dict) { yield return item.Value; } } } public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) { aItem = JSONNull.CreateOrGet(); } if (!string.IsNullOrEmpty(aKey)) { if (m_Dict.ContainsKey(aKey)) { m_Dict[aKey] = aItem; } else { m_Dict.Add(aKey, aItem); } } else { m_Dict.Add(Guid.NewGuid().ToString(), aItem); } } public override JSONNode Remove(string aKey) { if (!m_Dict.ContainsKey(aKey)) { return null; } JSONNode result = m_Dict[aKey]; m_Dict.Remove(aKey); return result; } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_Dict.Count) { return null; } KeyValuePair<string, JSONNode> keyValuePair = m_Dict.ElementAt(aIndex); m_Dict.Remove(keyValuePair.Key); return keyValuePair.Value; } public override JSONNode Remove(JSONNode aNode) { try { KeyValuePair<string, JSONNode> keyValuePair = m_Dict.Where((KeyValuePair<string, JSONNode> k) => k.Value == aNode).First(); m_Dict.Remove(keyValuePair.Key); return aNode; } catch { return null; } } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('{'); bool flag = true; if (inline) { aMode = JSONTextMode.Compact; } foreach (KeyValuePair<string, JSONNode> item in m_Dict) { if (!flag) { aSB.Append(','); } flag = false; if (aMode == JSONTextMode.Indent) { aSB.AppendLine(); } if (aMode == JSONTextMode.Indent) { aSB.Append(' ', aIndent + aIndentInc); } aSB.Append('"').Append(JSONNode.Escape(item.Key)).Append('"'); if (aMode == JSONTextMode.Compact) { aSB.Append(':'); } else { aSB.Append(" : "); } item.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine().Append(' ', aIndent); } aSB.Append('}'); } } public class JSONString : JSONNode { private string m_Data; public override JSONNodeType Tag => JSONNodeType.String; public override bool IsString => true; public override string Value { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONString(string aData) { m_Data = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('"').Append(JSONNode.Escape(m_Data)).Append('"'); } public override bool Equals(object obj) { if (base.Equals(obj)) { return true; } if (obj is string text) { return m_Data == text; } JSONString jSONString = obj as JSONString; if (jSONString != null) { return m_Data == jSONString.m_Data; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONNumber : JSONNode { private double m_Data; public override JSONNodeType Tag => JSONNodeType.Number; public override bool IsNumber => true; public override string Value { get { return m_Data.ToString(); } set { if (double.TryParse(value, out var result)) { m_Data = result; } } } public override double AsDouble { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONNumber(double aData) { m_Data = aData; } public JSONNumber(string aData) { Value = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append(m_Data); } private static bool IsNumeric(object value) { if (!(value is int) && !(value is uint) && !(value is float) && !(value is double) && !(value is decimal) && !(value is long) && !(value is ulong) && !(value is short) && !(value is ushort) && !(value is sbyte)) { return value is byte; } return true; } public override bool Equals(object obj) { if (obj == null) { return false; } if (base.Equals(obj)) { return true; } JSONNumber jSONNumber = obj as JSONNumber; if (jSONNumber != null) { return m_Data == jSONNumber.m_Data; } if (IsNumeric(obj)) { return Convert.ToDouble(obj) == m_Data; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONBool : JSONNode { private bool m_Data; public override JSONNodeType Tag => JSONNodeType.Boolean; public override bool IsBoolean => true; public override string Value { get { return m_Data.ToString(); } set { if (bool.TryParse(value, out var result)) { m_Data = result; } } } public override bool AsBool { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONBool(bool aData) { m_Data = aData; } public JSONBool(string aData) { Value = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append(m_Data ? "true" : "false"); } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is bool) { return m_Data == (bool)obj; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONNull : JSONNode { private static JSONNull m_StaticInstance = new JSONNull(); public static bool reuseSameInstance = true; public override JSONNodeType Tag => JSONNodeType.NullValue; public override bool IsNull => true; public override string Value { get { return "null"; } set { } } public override bool AsBool { get { return false; } set { } } public static JSONNull CreateOrGet() { if (reuseSameInstance) { return m_StaticInstance; } return new JSONNull(); } private JSONNull() { } public override Enumerator GetEnumerator() { return default(Enumerator); } public override bool Equals(object obj) { if ((object)this == obj) { return true; } return obj is JSONNull; } public override int GetHashCode() { return 0; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } internal class JSONLazyCreator : JSONNode { private JSONNode m_Node; private string m_Key; public override JSONNodeType Tag => JSONNodeType.None; public override JSONNode this[int aIndex] { get { return new JSONLazyCreator(this); } set { JSONArray jSONArray = new JSONArray(); jSONArray.Add(value); Set(jSONArray); } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this, aKey); } set { JSONObject jSONObject = new JSONObject(); jSONObject.Add(aKey, value); Set(jSONObject); } } public override int AsInt { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override float AsFloat { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0f; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override double AsDouble { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0.0; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override bool AsBool { get { JSONBool aVal = new JSONBool(aData: false); Set(aVal); return false; } set { JSONBool aVal = new JSONBool(value); Set(aVal); } } public override JSONArray AsArray { get { JSONArray jSONArray = new JSONArray(); Set(jSONArray); return jSONArray; } } public override JSONObject AsObject { get { JSONObject jSONObject = new JSONObject(); Set(jSONObject); return jSONObject; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONLazyCreator(JSONNode aNode) { m_Node = aNode; m_Key = null; } public JSONLazyCreator(JSONNode aNode, string aKey) { m_Node = aNode; m_Key = aKey; } private void Set(JSONNode aVal) { if (m_Key == null) { m_Node.Add(aVal); } else { m_Node.Add(m_Key, aVal); } m_Node = null; } public override void Add(JSONNode aItem) { JSONArray jSONArray = new JSONArray(); jSONArray.Add(aItem); Set(jSONArray); } public override void Add(string aKey, JSONNode aItem) { JSONObject jSONObject = new JSONObject(); jSONObject.Add(aKey, aItem); Set(jSONObject); } public static bool operator ==(JSONLazyCreator a, object b) { if (b == null) { return true; } return (object)a == b; } public static bool operator !=(JSONLazyCreator a, object b) { return !(a == b); } public override bool Equals(object obj) { if (obj == null) { return true; } return (object)this == obj; } public override int GetHashCode() { return 0; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } public static class JSON { public static JSONNode Parse(string aJSON) { return JSONNode.Parse(aJSON); } } } namespace XUnity.AutoTranslator.Plugin { internal class SceneLoadInformation { public SceneInformation ActiveScene { get; set; } public List<SceneInformation> LoadedScenes { get; set; } public SceneLoadInformation() { LoadedScenes = new List<SceneInformation>(); if (UnityFeatures.SupportsSceneManager) { LoadBySceneManager(); } else { LoadByApplication(); } } public void LoadBySceneManager() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); ActiveScene = new SceneInformation(((Scene)(ref activeScene)).buildIndex, ((Scene)(ref activeScene)).name); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); LoadedScenes.Add(new SceneInformation(((Scene)(ref sceneAt)).buildIndex, ((Scene)(ref sceneAt)).name)); } } public void LoadByApplication() { ActiveScene = new SceneInformation(Application.loadedLevel, Application.loadedLevelName); LoadedScenes.Add(new SceneInformation(Application.loadedLevel, Application.loadedLevelName)); } } internal class SceneInformation { public int Id { get; set; } public string Name { get; set; } public SceneInformation(int id, string name) { Id = id; Name = name; } } } namespace XUnity.AutoTranslator.Plugin.Utilities { internal static class TranslationScopeHelper { public static int GetScope(object ui) { if (Settings.EnableTranslationScoping) { try { Component val = (Component)((ui is Component) ? ui : null); if (val != null && Object.op_Implicit((Object)(object)val)) { return GetScopeFromComponent(val); } if (ui is GUIContent) { return -1; } return GetActiveSceneId(); } catch (MissingMemberException ex) { XuaLogger.AutoTranslator.Error((Exception)ex, "A 'missing member' error occurred while retriving translation scope. Disabling translation scopes."); Settings.EnableTranslationScoping = false; } } return -1; } private static int GetScopeFromComponent(Component component) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Scene scene = component.gameObject.scene; return ((Scene)(ref scene)).buildIndex; } public static int GetActiveSceneId() { if (UnityFeatures.SupportsSceneManager) { return GetActiveSceneIdBySceneManager(); } return GetActiveSceneIdByApplication(); } private static int GetActiveSceneIdBySceneManager() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).buildIndex; } public static void RegisterSceneLoadCallback(Action<int> sceneLoaded) { SceneManagerLoader.EnableSceneLoadScanInternal(sceneLoaded); } private static int GetActiveSceneIdByApplication() { return Application.loadedLevel; } } internal static class SceneManagerLoader { public static void EnableSceneLoadScanInternal(Action<int> sceneLoaded) { SceneManager.sceneLoaded += delegate(Scene arg1, LoadSceneMode arg2) { sceneLoaded(((Scene)(ref arg1)).buildIndex); }; } } internal static class TranslationScopes { public const int None = -1; } } namespace XUnity.AutoTranslator.Plugin.Core { public class AutoTranslationPlugin : MonoBehaviour, IMonoBehaviour, IMonoBehaviour_Update, IInternalTranslator, ITranslator, ITranslationRegistry { internal static AutoTranslationPlugin Current; private bool _hasResizedCurrentComponentDuringDiscovery; internal XuaWindow MainWindow; internal TranslationAggregatorWindow TranslationAggregatorWindow; internal TranslationAggregatorOptionsWindow TranslationAggregatorOptionsWindow; internal TranslationManager TranslationManager; internal TextTranslationCache TextCache; internal Dictionary<string, TextTranslationCache> PluginTextCaches = new Dictionary<string, TextTranslationCache>(StringComparer.OrdinalIgnoreCase); internal TextureTranslationCache TextureCache; internal UIResizeCache ResizeCache; internal SpamChecker SpamChecker; private Dictionary<string, UntranslatedText> CachedKeys = new Dictionary<string, UntranslatedText>(StringComparer.Ordinal); private List<Action<ComponentTranslationContext>> _shouldIgnore = new List<Action<ComponentTranslationContext>>(); private List<string> _textsToCopyToClipboardOrdered = new List<string>(); private HashSet<string> _textsToCopyToClipboard = new HashSet<string>(); private float _clipboardUpdated; private HashSet<string> _immediatelyTranslating = new HashSet<string>(); private bool _isInTranslatedMode = true; private bool _textHooksEnabled = true; private float _batchOperationSecondCounter; private bool _hasValidOverrideFont; private bool _hasOverridenFont; private bool _initialized; private bool _started; private bool _temporarilyDisabled; private string _requireSpriteRendererCheckCausedBy; private int _lastSpriteUpdateFrame = -1; private bool _isCalledFromSceneManager; private bool _translationReloadRequest; private bool _hasUiBeenSetup; private static bool _inputSupported; public void Initialize() { Current = this; Paths.Initialize(); HarmonyLoader.Load(); Settings.Configure(); DebugConsole.Enable(); InitializeHarmonyDetourBridge(); InitializeTextTranslationCaches(); HooksSetup.InstallTextHooks(); HooksSetup.InstallImageHooks(); HooksSetup.InstallSpriteRendererHooks(); HooksSetup.InstallTextGetterCompatHooks(); HooksSetup.InstallComponentBasedPluginTranslationHooks(); TextureCache = new TextureTranslationCache(); TextureCache.TextureTranslationFileChanged += TextureCache_TextureTranslationFileChanged; ResizeCache = new UIResizeCache(); TranslationManager = new TranslationManager(); TranslationManager.JobCompleted += OnJobCompleted; TranslationManager.JobFailed += OnJobFailed; TranslationManager.InitializeEndpoints(); SpamChecker = new SpamChecker(TranslationManager); UnityTextParsers.Initialize(); InitializeResourceRedirector(); ValidateConfiguration(); EnableSceneLoadScan(); LoadFallbackFont(); LoadTranslations(reload: false); XuaLogger.AutoTranslator.Info("Loaded XUnity.AutoTranslator into Unity [" + Application.unityVersion + "] game."); } private static void LoadFallbackFont() { try { if (!string.IsNullOrEmpty(Settings.FallbackFontTextMeshPro)) { Object orCreateFallbackFontTextMeshPro = FontCache.GetOrCreateFallbackFontTextMeshPro(); if (TMP_Settings_Properties.FallbackFontAssets == null) { XuaLogger.AutoTranslator.Info("Cannot use fallback font because it is not supported in this version."); return; } if (orCreateFallbackFontTextMeshPro == (Object)null) { XuaLogger.AutoTranslator.Warn("Could not load fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro); return; } ((IList)TMP_Settings_Properties.FallbackFontAssets.Get((object)null)).Add(orCreateFallbackFontTextMeshPro); XuaLogger.AutoTranslator.Info("Loaded fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to load fallback font for TextMesh Pro."); } } private static void InitializeHarmonyDetourBridge() { try { if (Settings.InitializeHarmonyDetourBridge) { InitializeHarmonyDetourBridgeSafe(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing harmony detour bridge."); } } private static void InitializeHarmonyDetourBridgeSafe() { HarmonyDetourBridge.Init(true, (Type)0); } private void InitializeTextTranslationCaches() { try { TextCache = new TextTranslationCache(); TextCache.TextTranslationFileChanged += TextCache_TextTranslationFileChanged; DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Settings.TranslationsPath, "plugins")); if (directoryInfo.Exists) { DirectoryInfo[] directories = directoryInfo.GetDirectories(); foreach (DirectoryInfo directoryInfo2 in directories) { TextTranslationCache value = new TextTranslationCache(directoryInfo2); PluginTextCaches.Add(directoryInfo2.Name, value); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing text translation caches."); } } private void TextCache_TextTranslationFileChanged() { _translationReloadRequest = true; } private void TextureCache_TextureTranslationFileChanged() { _translationReloadRequest = true; } private static void EnableLogAllLoadedResources() { ResourceRedirection.LogAllLoadedResources = true; } private void EnableTextAssetLoadedHandler() { new TextAssetLoadedHandler(); } private void InitializeResourceRedirector() { try { if (Settings.LogAllLoadedResources) { EnableLogAllLoadedResources(); } if (Settings.EnableTextAssetRedirector) { EnableTextAssetLoadedHandler(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing resource redirectors."); } } private void InitializeGUI() { Dis