Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalUtilities Public Testing v2.0.1
LethalUtilities.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.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalUtilities.Configuration; using LethalUtilitiesV2; using Microsoft.CodeAnalysis; using MonoMod.Utils; using Newtonsoft.Json; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LethalUtilities")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fc87b84960862e64d1b0d4748adc0adfa6ed415a")] [assembly: AssemblyProduct("LethalUtilities")] [assembly: AssemblyTitle("LethalUtilities")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Kyxino/LethalUtilities")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 LethalUtilitiesV2 { public enum RunConfig { Enabled, UseLoadSettings, ConfigDisabled } public class Utils { [CompilerGenerated] private sealed class <HarmonyEnumerator>d__3 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public IEnumerator Enumerator; public Action EnumeratorPrefix; public Action EnumeratorPostfix; public Action<object> YieldPrefix; public Func<object, object> YieldAction; public Action<object> YieldPostfix; private object <CurrentItem>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <HarmonyEnumerator>d__3(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <CurrentItem>5__1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (EnumeratorPrefix != null) { EnumeratorPrefix(); } break; case 1: <>1__state = -1; if (YieldPostfix != null) { YieldPostfix(<CurrentItem>5__1); } <CurrentItem>5__1 = null; break; } if (Enumerator.MoveNext()) { <CurrentItem>5__1 = Enumerator.Current; if (YieldPrefix != null) { YieldPrefix(<CurrentItem>5__1); } <>2__current = ((YieldAction != null) ? YieldAction(<CurrentItem>5__1) : null); <>1__state = 1; return true; } if (EnumeratorPostfix != null) { EnumeratorPostfix(); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static T InvokeMethod<T>(object OBJECT, string METHOD, object[] PARAMETERS = null) { return (T)OBJECT.GetType().GetMethod(METHOD, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Invoke(OBJECT, PARAMETERS); } private static T GetField<T>(object OBJECT, string FIELD) { return (T)OBJECT.GetType().GetField(FIELD, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(OBJECT); } private static T SetField<T>(object OBJECT, string FIELD, T VALUE) { OBJECT.GetType().GetField(FIELD, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).SetValue(OBJECT, VALUE); return VALUE; } [IteratorStateMachine(typeof(<HarmonyEnumerator>d__3))] public static IEnumerator HarmonyEnumerator(IEnumerator Enumerator, Action EnumeratorPrefix = null, Action EnumeratorPostfix = null, Action<object> YieldPrefix = null, Func<object, object> YieldAction = null, Action<object> YieldPostfix = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <HarmonyEnumerator>d__3(0) { Enumerator = Enumerator, EnumeratorPrefix = EnumeratorPrefix, EnumeratorPostfix = EnumeratorPostfix, YieldPrefix = YieldPrefix, YieldAction = YieldAction, YieldPostfix = YieldPostfix }; } } public static class ObjectExtensions { public static string Val(this object Value) { return string.Format("{0} ({1})", Value, (Value != null) ? ((object)Value.GetType()) : ((object)"N/A")); } } [BepInPlugin("Kyxino-LUv2", "Ky-LethalUtilities", "2.0.1")] public class UtilsMod : BaseUnityPlugin { [JsonConverter(typeof(IL_SubField))] internal class IL_SubFieldConverter : JsonConverter<IL_SubField> { public override bool CanRead => true; public override bool CanWrite => false; public override void WriteJson(JsonWriter writer, IL_SubField value, JsonSerializer serializer) { } public override IL_SubField ReadJson(JsonReader reader, Type objectType, IL_SubField existingValue, bool hasExistingValue, JsonSerializer serializer) { return IL_SubField.Parse(serializer.Deserialize<List<string>>(reader)); } } public class IL_SubField { public static Dictionary<int, IL_SubField> HashChecks = new Dictionary<int, IL_SubField>(); public IL_Field Field; public List<string> SubFieldList; public object SubFieldValue; public Type SubFieldType; public bool IsLocal; public int LocalHash; public IL_SubField(IL_Field Field, List<string> SubFieldList, bool IsLocal = false) { this.Field = Field; this.SubFieldList = SubFieldList; SubFieldType = (SubFieldValue = GetSubFieldValue(Field.OriginalValue))?.GetType(); this.IsLocal = IsLocal; HashChecks.TryAdd(GetHashCode(), this); } public object GetSubFieldValue(object Field) { if (IsLocal) { return Field; } Logger("GetSubFieldValue", (LogLevel)16, (object)"START"); Logger("GetSubFieldValue", (LogLevel)16, Field); foreach (string subField in SubFieldList) { try { Logger("GetSubFieldValue", (LogLevel)16, (object)$"Field: {Field} ({Field?.GetType()}) | SubField: {subField}"); MethodInfo methodInfo = Field?.GetType()?.GetMethod("get_" + subField); Field = ((!(methodInfo != null)) ? Field?.GetType()?.GetField(subField)?.GetValue(Field) : methodInfo.Invoke(Field, Array.Empty<object>())); Logger("GetSubFieldValue", (LogLevel)8, (object)$"Field: {Field}"); } catch (Exception ex) { Logger("GetSubFieldValue", (LogLevel)2, (object)("SubField Error | " + GeneralExtensions.Join<string>((IEnumerable<string>)SubFieldList, (Func<string, string>)null, ", ") + ": " + ex.Message)); return null; } } Logger("GetSubFieldValue", (LogLevel)16, (object)"END"); return Field; } public void SetSubFieldValue(object Field, object Value) { if (IsLocal) { return; } Logger("SetSubFieldValue", (LogLevel)16, (object)"START"); Logger("SetSubFieldValue", (LogLevel)16, Field); for (int i = 0; i < SubFieldList.Count; i++) { string text = SubFieldList[i]; try { Logger("SetSubFieldValue", (LogLevel)16, Field); if (i == SubFieldList.Count - 1) { MethodInfo methodInfo = Field?.GetType()?.GetMethod("set_" + text); if (methodInfo != null) { methodInfo.Invoke(Field = Value, Array.Empty<object>()); } else { Field?.GetType()?.GetField(text)?.SetValue(Field, Field = Value); } } else { Field = Field?.GetType()?.GetMethod("get_" + text)?.Invoke(Field, Array.Empty<object>()) ?? Field?.GetType().GetField(text).GetValue(Field); } Logger("SetSubFieldValue", (LogLevel)8, Field); } catch (Exception ex) { Logger("SetSubFieldValue", (LogLevel)2, (object)string.Format("SubField Set Error {0}/{1} | {2}: {3}", i + 1, SubFieldList.Count, GeneralExtensions.Join<string>((IEnumerable<string>)SubFieldList, (Func<string, string>)null, ", "), ex.Message)); return; } } Logger("SetSubFieldValue", (LogLevel)16, (object)"END"); } public static IL_SubField Parse(List<string> SearchList, object FieldValue = null, bool CanSet = false, bool LiveValue = false) { List<string> list = SearchList.Where((string x) => x.Contains("::")).ToList(); List<string> SubFieldList = SearchList.Where((string x) => !x.Contains("::")).ToList(); bool flag = list.Count == 0; if (flag) { list = SubFieldList; SubFieldList = new List<string>(); } int num = list.FindIndex((string x) => x.StartsWith("=")); if (num == -1) { return null; } List<string> range = list.GetRange(0, num); string text = list[num]; string fieldTarget = text.Substring(1, text.Length - 1); List<string> range2 = list.GetRange(num + 1, list.Count - num - 1); List<string> RawFieldList = range.Union(new <>z__ReadOnlySingleElementList<string>(list[num])).Union(range2).ToList(); IL_Field iL_Field = (flag ? null : IL_Field.CachedIL_Fields.FirstOrDefault((IL_Field x) => x.RawFieldList != null && (RawFieldList?.SequenceEqual(x.RawFieldList) ?? false))); if (iL_Field == null) { iL_Field = new IL_Field(range, fieldTarget, range2, FieldValue, CanSet, LiveValue, flag); if (!flag) { IL_Field.CachedIL_Fields.Add(iL_Field); } } IL_SubField iL_SubField = (flag ? null : iL_Field.SubFields.FirstOrDefault((IL_SubField x) => SubFieldList.SequenceEqual(x.SubFieldList))); if (iL_SubField == null) { iL_Field.SubFields.Add(iL_SubField = new IL_SubField(iL_Field, SubFieldList, flag)); } return iL_SubField; } public override int GetHashCode() { return HashCode.Combine(Field, SubFieldList); } } public class IL_Field : IEquatable<IL_Field> { public static List<IL_Field> CachedIL_Fields = new List<IL_Field>(); public List<string> PreFieldLook; public object OriginalValue; public object FieldValue; public Type FieldType; public IL_Fragment FieldTarget; public List<string> PostFieldLook; public List<string> RawFieldList; public bool CanSet; public bool LiveValue; public bool IsLocal; public List<IL_SubField> SubFields; public IL_Field(List<string> PreFieldLook, string FieldTarget, List<string> PostFieldLook, object FieldValue = null, bool CanSet = false, bool LiveValue = false, bool IsLocal = false) { this.PreFieldLook = PreFieldLook; OriginalValue = FieldValue; this.FieldValue = FieldValue; FieldType = FieldValue?.GetType(); this.FieldTarget = new IL_Fragment(FieldTarget); this.PostFieldLook = PostFieldLook; RawFieldList = PreFieldLook.Union(new <>z__ReadOnlySingleElementList<string>("=" + FieldTarget)).Union(PostFieldLook).ToList(); this.CanSet = CanSet; this.LiveValue = LiveValue; SubFields = new List<IL_SubField>(1) { new IL_SubField(this, new List<string>()) }; this.IsLocal = IsLocal; } public override bool Equals(object obj) { return obj is IL_Field iL_Field && PreFieldLook.Equals(iL_Field.PreFieldLook) && FieldTarget.Equals(iL_Field.FieldTarget) && PostFieldLook.Equals(iL_Field.PostFieldLook); } public bool Equals(IL_Field IL_Obj) { return PreFieldLook.Equals(IL_Obj.PreFieldLook) && FieldTarget.Equals(IL_Obj.FieldTarget); } public override int GetHashCode() { return HashCode.Combine(PreFieldLook, FieldTarget, PostFieldLook); } } public class IL_Fragment { public static Dictionary<string, IL_Fragment> Cached_Fragments = new Dictionary<string, IL_Fragment>(); public List<string> Raw; public List<string> Unorganized; public string SpecificTarget; public IL_Fragment(string Target) { Raw = Target.Split(' ').ToList(); Unorganized = Raw.Where((string x) => !x.Contains("::")).ToList(); SpecificTarget = Raw.FirstOrDefault((string x) => x.Contains("::")); } public bool Match(IL_Fragment OpNameSplit) { return OpNameSplit.SpecificTarget == SpecificTarget || (SpecificTarget != null && OpNameSplit.SpecificTarget != null && SpecificTarget.Contains(OpNameSplit.SpecificTarget) && OpNameSplit.Unorganized.All((string Partial) => Unorganized.FirstOrDefault((string x) => x.Contains(Partial)) != null)); } public override string ToString() { return GeneralExtensions.Join<string>((IEnumerable<string>)Raw, (Func<string, string>)null, " "); } } public class CachedMethods { public static string Path = Directory.GetParent(Assembly.GetExecutingAssembly().Location)?.ToString() + "\\methods.LU.cache"; public List<string> Methods = new List<string>(); public Dictionary<string, string> Mods = new Dictionary<string, string>(); public List<string> LUHashes = new List<string>(); public string GameUUID; public string LU_UUID; } public static BepInPlugin Metadata = MetadataHelper.GetMetadata(typeof(UtilsMod)); private readonly Harmony HarmonyX = new Harmony("Kyxino-LUv2"); public static ManualLogSource MLS = Logger.CreateLogSource("LethalUtilitiesV2"); public List<JsonVarLUFile> LUFiles; public static Dictionary<string, ManualLogSource> Loggers = new Dictionary<string, ManualLogSource>(); public static Dictionary<IL_SubField, List<JsonVarLU>> VariablesLU = new Dictionary<IL_SubField, List<JsonVarLU>>(); public static MethodInfo ManageField = AccessTools.Method(typeof(UtilsMod), "ManagingField", (Type[])null, (Type[])null); public static MethodInfo TypeMethod = AccessTools.Method(typeof(Type), "GetTypeFromHandle", (Type[])null, (Type[])null); public static int MethodsChanged = 0; public static string TranspileMethodName; private void Awake() { ConfigUtilities.AddAllTypes(); JsonConvert.DefaultSettings = () => new JsonSerializerSettings { Converters = new List<JsonConverter>(1) { (JsonConverter)(object)new IL_SubFieldConverter() } }; LUFiles = new List<JsonVarLUFile>(); string[] files = Directory.GetFiles(Paths.BepInExRootPath, "*.LU.json", SearchOption.AllDirectories); foreach (string path in files) { string text = File.ReadAllText(path); JsonVarLUFile jsonVarLUFile = JsonConvert.DeserializeObject<JsonVarLUFile>(text); jsonVarLUFile.Hash = Extensions.ToHexadecimalString(MD5.Create().ComputeHash(Encoding.Default.GetBytes(text))); LUFiles.Add(jsonVarLUFile); string folderName = null; string fileName = null; string categoryName = null; NetworkedConfigSync syncType = NetworkedConfigSync.Unspecified; bool? includesRaw = null; for (int j = 0; j < jsonVarLUFile.Variables.Count; j++) { JsonVarLU jsonVarLU = jsonVarLUFile.Variables[j]; if (jsonVarLUFile.Settings.RolloverFolder) { JsonVarLU jsonVarLU2 = jsonVarLU; folderName = jsonVarLU2.FolderName ?? (jsonVarLU2.FolderName = folderName); } if (jsonVarLUFile.Settings.RolloverFile) { JsonVarLU jsonVarLU2 = jsonVarLU; fileName = jsonVarLU2.FileName ?? (jsonVarLU2.FileName = fileName); } if (jsonVarLUFile.Settings.RolloverCategory) { JsonVarLU jsonVarLU2 = jsonVarLU; categoryName = jsonVarLU2.CategoryName ?? (jsonVarLU2.CategoryName = categoryName); } if (jsonVarLUFile.Settings.RolloverSyncType) { if (jsonVarLU.SyncType == NetworkedConfigSync.Unspecified) { jsonVarLU.SyncType = syncType; } else { syncType = jsonVarLU.SyncType; } } if (jsonVarLUFile.Settings.RolloverRaw) { if (!jsonVarLU.IncludesRaw.HasValue) { jsonVarLU.IncludesRaw = includesRaw; } else { includesRaw = jsonVarLU.IncludesRaw; } } } } LUFiles.Sort((JsonVarLUFile L, JsonVarLUFile N) => L.Settings.Priority.CompareTo(N.Settings.Priority)); foreach (JsonVarLU item in LUFiles.SelectMany((JsonVarLUFile LUFile) => LUFile.Variables)) { if (item.SearchForValue == null) { continue; } item.WaitFor.Add(item.SearchForValue.Field); if (!VariablesLU.TryGetValue(item.SearchForValue, out var value)) { VariablesLU.TryAdd(item.SearchForValue, value = new List<JsonVarLU>()); } if (!value.Contains(item)) { value.Add(item); } if (item.SearchForKey == null) { continue; } item.WaitFor.Add(item.SearchForKey.Field); if (!VariablesLU.TryGetValue(item.SearchForKey, out var value2)) { VariablesLU.TryAdd(item.SearchForKey, value2 = new List<JsonVarLU>()); } if (!value2.Contains(item)) { value2.Add(item); } if (item.ValidKeys != null) { if (!VariablesLU.TryGetValue(item.ValidKeys, out var value3)) { VariablesLU.TryAdd(item.ValidKeys, value3 = new List<JsonVarLU>()); } if (!value3.Contains(item)) { value3.Add(item); } } } ApplyChanges(); MLS.LogInfo((object)"All enabled patches have been executed."); } public static void Logger(string Name, LogLevel LogLevel, object Data) { } public static void Logger(string Name, object Data, LogLevel LogLevel = 16) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Logger(Name, LogLevel, Data); } public static object HandleVar(JsonVarLU Var, object ModifyValue) { ConfigEntry<object> entry = Var.Entry; ConfigUtilities.TypeConverterBase converter = entry.EntrySettings.GetConverter(); if (converter.TypeEnum == ConfigUtilities.TypeConverterEnum.Variable) { Logger("LoggerVarTest", (LogLevel)2, (object)("Variable? " + Var.FolderName + "." + Var.FileName + "." + Var.CategoryName + "." + Var.VariableName)); if (converter.KeyType == typeof(LU_EQ)) { return (Var.Entry.Value is LU_EQ lU_EQ) ? lU_EQ.CalcFormula(ModifyValue.ToString()) : null; } if (converter.KeyType == typeof(string)) { return Var.Entry.Value?.ToString(); } if (converter.KeyType == typeof(bool)) { return Var.Entry.Value; } return null; } if (converter.TypeEnum == ConfigUtilities.TypeConverterEnum.Dictionary) { Logger("LoggerVarTest", (LogLevel)2, (object)("Dictionary? " + Var.FolderName + "." + Var.FileName + "." + Var.CategoryName + "." + Var.VariableName)); if (converter.ValueType == typeof(LU_EQ)) { object obj = converter.ConvertToHash(entry.Value); Dictionary<int, LU_EQ> dictionary = (Dictionary<int, LU_EQ>)obj; IL_SubField searchForKey = Var.SearchForKey; Logger("HandleVar", (LogLevel)1, (object)$"VALUES: {searchForKey?.Field?.OriginalValue} | {searchForKey?.Field?.FieldValue}"); object obj2 = searchForKey?.GetSubFieldValue(searchForKey?.Field?.OriginalValue); int? num = obj2?.GetHashCode(); if (!num.HasValue) { return null; } List<object> usedKeys = entry.EntrySettings.UsedKeys; if (true && !usedKeys.Contains(obj2)) { usedKeys.Add(obj2); entry.ConfigFile.Save(); } LU_EQ value; LU_EQ lU_EQ2 = (dictionary.TryGetValue(num.Value, out value) ? value : LU_EQ.Default); Logger("HandleVar", (LogLevel)1, (object)$"HASH ({num}:{lU_EQ2.Formula}) | x = {ModifyValue}"); return lU_EQ2.CalcFormula(ModifyValue.ToString()); } } return null; } public static object ManagingField(object Field, int LoggedSubField_Hash, Type FieldType, bool IsSetting) { if (!IL_SubField.HashChecks.TryGetValue(LoggedSubField_Hash, out var value)) { return Field; } IL_Field iL_Field = value?.Field; IL_Fragment iL_Fragment = iL_Field?.FieldTarget; Logger("ManagingField", (LogLevel)8, (object)"STARTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"); Logger("ManagingField", (LogLevel)16, (object)(IsSetting ? "Setting?" : "Getting?")); Logger("ManagingField", (LogLevel)1, (object)string.Format("{0} FIELD | Name: {1} | Value: {2} | Type: {3} | IsSetting: {4}", IsSetting ? "SETTING" : "GETTING", iL_Fragment?.ToString() ?? "N/A", Field, FieldType, IsSetting)); if (!iL_Field.LiveValue) { iL_Field.LiveValue = true; iL_Field.OriginalValue = Field; } iL_Field.FieldValue = Field; object obj = (iL_Field.IsLocal ? Field : iL_Field.OriginalValue); value.SubFieldType = (value.SubFieldValue = value.GetSubFieldValue(obj)).GetType(); if (!VariablesLU.TryGetValue(value, out var value2)) { return Field; } Logger("ManagingField", (LogLevel)1, (object)string.Format("{0} {1}", iL_Fragment, IsSetting ? "SET" : "GET")); bool flag = false; object obj2 = obj; Logger("ManagingField", (LogLevel)1, (object)$"Pre-Value: {obj2.Val()}:({value.SubFieldType}) | {Field} ({Field.GetType()})"); foreach (JsonVarLU item in value2) { Logger("ManagingField", (LogLevel)1, (object)string.Format("InList: {0}.{1} | {2} | {3}:{4}", item.CategoryName, item.VariableName, item.WaitFor.Count, item.SearchForKey?.Field?.FieldTarget?.ToString() ?? "N/A", item.SearchForValue?.Field?.FieldTarget?.ToString() ?? "N/A")); if (item.WaitFor.Contains(iL_Field)) { item.WaitFor.Remove(iL_Field); } if (item.ValidKeys != null) { List<object> usedKeys = item.UsedKeys; if (usedKeys != null) { object subFieldValue = item.ValidKeys.GetSubFieldValue(item.ValidKeys.Field?.FieldValue); if (subFieldValue != null && !usedKeys.Contains(subFieldValue)) { usedKeys.Add(subFieldValue); item.Entry?.ConfigFile?.Save(); } } } if (item.WaitFor.Count <= 0) { item.SaveToFile(); if (item.SearchForValue.Field.FieldTarget == iL_Field.FieldTarget && item.IsVarEnabled()) { obj2 = HandleVar(item, obj2); flag = true; Logger("ManagingField", (LogLevel)1, (object)("Cur-Value: " + obj2.Val())); } } } if (!flag) { return Field; } Logger("ManagingField", (LogLevel)1, (object)$"Value ({iL_Fragment}): {obj2.Val()} | {iL_Field.FieldValue.Val()} : {value.SubFieldValue.Val()}"); Logger("ManagingField", (LogLevel)1, (object)("Post1?: " + obj2.Val())); obj2 = obj2.ToString(); if (value.SubFieldType == typeof(int)) { obj2 = (int.TryParse((string)obj2, out var result) ? ((object)result) : null); } else if (value.SubFieldType == typeof(float)) { obj2 = (float.TryParse((string)obj2, out var result2) ? ((object)result2) : null); } else if (value.SubFieldType == typeof(double)) { obj2 = (double.TryParse((string)obj2, out var result3) ? ((object)result3) : null); } Logger("ManagingField", (LogLevel)1, (object)("Post2?: " + obj2.Val())); Logger("ManagingField", (LogLevel)1, (object)("Post-Value: " + obj2.Val() + " | " + iL_Field.FieldValue.Val() + " : " + value.SubFieldValue.Val())); Logger("ManagingField", (LogLevel)8, (object)"ENDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"); if (IsSetting) { value.SetSubFieldValue(obj, obj2); } object obj3 = ((value.SubFieldList.Count == 0) ? obj2 : Field); Logger("ManagingField", (LogLevel)8, (object)("RESULT " + obj3.Val())); return obj3; } public static KeyValuePair<IL_SubField, List<JsonVarLU>> GetVariable(List<CodeInstruction> InstructionList, int i, string SpecificMethod) { IL_Fragment OpNameSplit = new IL_Fragment(((object)InstructionList[i]).ToString()); foreach (KeyValuePair<IL_SubField, List<JsonVarLU>> item in VariablesLU.Where((KeyValuePair<IL_SubField, List<JsonVarLU>> x) => OpNameSplit.Match(x.Key.Field.FieldTarget) && x.Value.FirstOrDefault((JsonVarLU y) => y.SearchAt == null || y.SearchAt.FirstOrDefault((string z) => SpecificMethod.Contains(z)) != null) != null)) { bool flag = true; IL_Field field = item.Key.Field; List<string> preFieldLook = field.PreFieldLook; List<string> postFieldLook = field.PostFieldLook; for (int j = 0; j < preFieldLook.Count && flag; j++) { string pattern = preFieldLook[j]; int num = i + (j - preFieldLook.Count); if (!(flag = 0 <= num && num < InstructionList.Count)) { break; } CodeInstruction val = InstructionList[num]; flag = Regex.IsMatch(((object)val).ToString(), pattern) || Regex.IsMatch(val.opcode.ToString(), pattern); } if (!flag) { continue; } for (int k = 0; k < postFieldLook.Count && flag; k++) { string pattern2 = postFieldLook[k]; int num2 = i + k + 1; if (!(flag = 0 <= num2 && num2 < InstructionList.Count)) { break; } CodeInstruction val2 = InstructionList[num2]; flag = Regex.IsMatch(((object)val2).ToString(), pattern2) || Regex.IsMatch(val2.opcode.ToString(), pattern2); } if (!flag) { continue; } return item; } return default(KeyValuePair<IL_SubField, List<JsonVarLU>>); } private static IEnumerable<CodeInstruction> DecorateInstructions(IEnumerable<CodeInstruction> instructions) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected O, but got Unknown //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(); bool flag = false; List<CodeInstruction> list2 = instructions.ToList(); for (int i = 0; i < list2.Count; i++) { CodeInstruction val = list2[i]; bool flag2 = val.opcode == OpCodes.Stfld || val.opcode == OpCodes.Stsfld; bool flag3 = val.opcode == OpCodes.Call; bool flag4 = val.opcode == OpCodes.Ldc_R4; if (!flag2 && !flag3 && !flag4 && val.opcode != OpCodes.Ldfld && val.opcode != OpCodes.Ldsfld) { list.Add(val); continue; } KeyValuePair<IL_SubField, List<JsonVarLU>> variable = GetVariable(list2, i, TranspileMethodName); if (variable.Value == null) { list.Add(val); continue; } Type type = (flag4 ? val.operand.GetType() : (flag3 ? ((MethodInfo)val.operand).ReturnType : ((FieldInfo)val.operand).FieldType)); flag = true; if (!flag2) { list.Add(val); } IL_Field field = variable.Key.Field; field.CanSet |= flag2; field.FieldType = type; list.Add(new CodeInstruction(OpCodes.Box, (object)type)); list.Add(new CodeInstruction(OpCodes.Ldc_I4, (object)variable.Key.GetHashCode())); list.Add(new CodeInstruction(OpCodes.Ldtoken, (object)type)); list.Add(new CodeInstruction(OpCodes.Call, (object)TypeMethod)); list.Add(new CodeInstruction(OpCodes.Ldc_I4, (object)(flag2 ? 1 : 0))); list.Add(new CodeInstruction(OpCodes.Call, (object)ManageField)); list.Add(new CodeInstruction(OpCodes.Unbox_Any, (object)type)); if (flag2) { list.Add(val); } } if (flag) { MethodsChanged++; } IEnumerable<CodeInstruction> result; if (!flag) { result = instructions; } else { IEnumerable<CodeInstruction> enumerable = list; result = enumerable; } return result; } public void ApplyChanges() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown string text = Assembly.GetExecutingAssembly().ManifestModule.ModuleVersionId.ToString(); HarmonyMethod val = new HarmonyMethod(((object)this).GetType(), "DecorateInstructions", (Type[])null); Dictionary<string, PluginInfo> pluginInfos = Chainloader.PluginInfos; pluginInfos.Remove("com.sinai.unityexplorer"); pluginInfos.Remove(HarmonyX.Id); Stopwatch stopwatch = Stopwatch.StartNew(); CachedMethods Cached = JsonConvert.DeserializeObject<CachedMethods>(File.Exists(CachedMethods.Path) ? File.ReadAllText(CachedMethods.Path) : "{}"); bool flag = true; foreach (JsonVarLUFile lUFile in LUFiles) { flag &= Cached.LUHashes.Contains(lUFile.Hash); if (!flag) { break; } } if (flag) { flag &= text == Cached.LU_UUID; } CachedMethods cachedMethods = new CachedMethods(); cachedMethods.LU_UUID = text; cachedMethods.LUHashes = LUFiles.Select((JsonVarLUFile x) => x.Hash).ToList(); IEnumerable<MethodInfo> first = Array.Empty<MethodInfo>(); foreach (PluginInfo item in pluginInfos.Select((KeyValuePair<string, PluginInfo> x) => x.Value)) { if (!((Object)(object)item.Instance == (Object)null)) { Assembly assembly = Assembly.GetAssembly(((object)item.Instance).GetType()); IEnumerable<MethodInfo> enumerable = ((IEnumerable<Type>)AccessTools.GetTypesFromAssembly(assembly)).SelectMany((Func<Type, IEnumerable<MethodInfo>>)AccessTools.GetDeclaredMethods).Where(FilterUnpatchable); cachedMethods.Mods.TryAdd(item.Metadata.GUID, assembly.ManifestModule.ModuleVersionId.ToString()); if (flag && Cached.Mods.TryGetValue(item.Metadata.GUID, out var value) && value == assembly.ManifestModule.ModuleVersionId.ToString()) { enumerable = enumerable.Where(FilterCached); } first = first.Union(enumerable); } } Assembly assembly2 = Assembly.GetAssembly(typeof(Item)); IEnumerable<MethodInfo> enumerable2 = ((IEnumerable<Type>)AccessTools.GetTypesFromAssembly(assembly2)).SelectMany((Func<Type, IEnumerable<MethodInfo>>)AccessTools.GetDeclaredMethods).Where(FilterUnpatchable); first = ((!((cachedMethods.GameUUID = assembly2.ManifestModule.ModuleVersionId.ToString()) == Cached.GameUUID && flag)) ? first.Union(enumerable2) : first.Union(enumerable2.Where(FilterCached))); MLS.LogWarning((object)$"Attempting to patch up to {first.Count()} methods."); foreach (MethodInfo item2 in first) { int methodsChanged = MethodsChanged; try { TranspileMethodName = $"{item2.DeclaringType}::{item2.Name}"; HarmonyX.Patch((MethodBase)item2, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); if (MethodsChanged - methodsChanged == 1) { cachedMethods.Methods.Add($"{item2.ReturnType} {TranspileMethodName}"); } } catch (Exception ex) { MLS.LogFatal((object)string.Format("Failed to patch {0} ({1}) with error: {2}\n{3}", item2, (MethodsChanged - methodsChanged == 1) ? "CHANGED" : "UNCHANGED", ex.Message, ex.GetBaseException())); } } File.WriteAllText(CachedMethods.Path, JsonConvert.SerializeObject((object)cachedMethods)); MLS.LogMessage((object)$"Done adjusting {MethodsChanged}/{first.Count()} methods. Time: {stopwatch.Elapsed}"); bool FilterCached(MethodInfo x) { return Cached.Methods.Contains($"{x.ReturnType} {x.DeclaringType}::{x.Name}"); } static bool FilterUnpatchable(MethodInfo x) { return !x.ContainsGenericParameters && !x.IsGenericMethod && MethodBaseExtensions.HasMethodBody((MethodBase)x); } } } public class JsonVarLU { [JsonProperty("SearchAt")] public List<string> SearchAt; [JsonProperty("SearchForValue")] public UtilsMod.IL_SubField SearchForValue; [JsonProperty("SearchForKey")] public UtilsMod.IL_SubField SearchForKey; [JsonProperty("ValidKeys")] public UtilsMod.IL_SubField ValidKeys; [JsonProperty("FolderName")] public string FolderName; [JsonProperty("FileName")] public string FileName; [JsonProperty("CategoryName")] public string CategoryName; [JsonProperty("VariableName")] public string VariableName; [JsonProperty("Description")] public string Description; [JsonProperty("SectionOrder")] public int SectionOrder; [JsonProperty("SyncType")] public NetworkedConfigSync SyncType; [JsonProperty("IsVarList")] public bool IsVarList; [JsonProperty("IncludesRaw")] public bool? IncludesRaw; [JsonProperty("IncludeAccessedKeys")] public bool IncludeAccessedKeys; public ConfigEntry<object> Entry; public List<object> UsedKeys = new List<object>(); public List<UtilsMod.IL_Field> WaitFor = new List<UtilsMod.IL_Field>(); public ConfigFile VarConfigFile; public bool Saved = false; public static Dictionary<string, ConfigFile> Files = new Dictionary<string, ConfigFile>(); public bool IsVarEnabled() { switch (VarConfigFile.ConfigEnabledVar.Value) { case LoadSettings.ApplyConfig: return true; case LoadSettings.Disabled: return false; default: { List<string> value = VarConfigFile.LoadSettingsVar.Value; return value.Contains(CategoryName) || value.Contains(VariableName); } } } public void SaveToFile() { if (!Saved) { Saved = true; UtilsMod.IL_Field iL_Field = SearchForValue?.Field; UtilsMod.IL_Field iL_Field2 = SearchForKey?.Field; Type type = SearchForKey?.SubFieldType; object defaultValue = SearchForValue?.GetSubFieldValue(SearchForValue.Field.OriginalValue); Type type2 = SearchForValue.SubFieldType; if (type2 == typeof(int) || type2 == typeof(float) || type2 == typeof(double)) { type2 = typeof(LU_EQ); defaultValue = new LU_EQ(); } ConfigEntrySettings configEntrySettings = new ConfigEntrySettings(null, CategoryName, VariableName) { KeyType = type, ValueType = type2, Description = Description, SectionOrder = SectionOrder, UsedKeys = UsedKeys, Rule = (IsVarList ? LU_Direction.DictionaryKey : LU_Direction.None), IncludeAccessedKeys = IncludeAccessedKeys, SyncType = SyncType }; ConfigUtilities.TypeConverterBase converter = configEntrySettings.GetConverter(); if (IsVarList && converter.GetDefaultValue != null) { defaultValue = converter.GetDefaultValue(type, type2); } string folderName = FolderName; string fileName = FileName; string text = Paths.BepInExRootPath + "\\LethalUtilities" + ((folderName != null) ? ("\\" + folderName) : "") + "\\" + fileName + ".cfg"; if (!Files.TryGetValue(text, out VarConfigFile)) { Files.TryAdd(text, VarConfigFile = new ConfigFile(text, saveOnInit: true, UtilsMod.Metadata)); VarConfigFile.ConfigEnabledVar = VarConfigFile.Bind(new ConfigEntrySettings(null, "ACTIVE SETTINGS", "ConfigEnabled") { ValueType = typeof(LoadSettings), SectionOrder = -999, Rule = LU_Direction.None, SyncType = NetworkedConfigSync.SyncWithHost }, LoadSettings.OnlyLoadSettings); VarConfigFile.LoadSettingsVar = VarConfigFile.Bind(new ConfigEntrySettings(null, "ACTIVE SETTINGS", "LoadSettings") { ValueType = typeof(string), SectionOrder = -999, Rule = LU_Direction.DictionaryValue, SyncType = NetworkedConfigSync.SyncWithHost }, new List<string>()); } Entry = VarConfigFile.Bind(configEntrySettings, defaultValue, (!IncludesRaw.GetValueOrDefault()) ? null : SearchForValue?.GetSubFieldValue(SearchForValue.Field.OriginalValue)?.ToString()); } } } public class JsonVarLUSettings { [JsonProperty("Priority")] public int Priority; [JsonProperty("RolloverFolder")] public bool RolloverFolder; [JsonProperty("RolloverFile")] public bool RolloverFile; [JsonProperty("RolloverCategory")] public bool RolloverCategory; [JsonProperty("RolloverSyncType")] public bool RolloverSyncType; [JsonProperty("RolloverRaw")] public bool RolloverRaw; } public class JsonVarLUFile { [JsonProperty("Settings")] public JsonVarLUSettings Settings; [JsonProperty("Variables")] public List<JsonVarLU> Variables; public string Hash; } public class LU_EQ { public static LU_EQ Default = new LU_EQ(); public string Formula; private static readonly List<List<string>> IDK_TableThing = new List<List<string>>(2) { new List<string>(1) { "^" }, new List<string>(2) { "*", "/" } }; public LU_EQ(string StringFormula = "1x") { Formula = StringFormula; base..ctor(); } public string CalcFormula(string Value) { List<string> list = Convert(Formula); int num = 0; while (true) { num++; string s = ((num > 1) ? list.ElementAtOrDefault(num - 2) : null); string s2 = ((num > 0) ? list.ElementAtOrDefault(num - 1) : null); string text = list.ElementAtOrDefault(num); UtilsMod.Logger("LU_EQ", (LogLevel)4, (object)string.Join(" ", list)); if (text == null) { break; } float.TryParse(s, out var result); float.TryParse(s2, out var result2); switch (text) { case "+": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = (result + result2).ToString(); break; case "-": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = (result - result2).ToString(); break; case "*": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = (result * result2).ToString(); break; case "/": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = (result / result2).ToString(); break; case "^": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = MathF.Pow(result, result2).ToString(); break; case "%": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = (result % result2).ToString(); break; case ">": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = ((result > result2) ? "1" : "0"); break; case "<": list.RemoveAt(num--); list.RemoveAt(num--); list[num] = ((result < result2) ? "1" : "0"); break; case "x": list[num] = Value; break; } } return list.FirstOrDefault(); } private static void IDK(List<object> Parent) { foreach (List<object> item3 in Parent.Where((object ObjectTesting) => ObjectTesting is List<object>).Cast<List<object>>()) { IDK(item3); foreach (List<string> item4 in IDK_TableThing) { int num = 0; while (true) { object item = item3[num]; num++; if (num >= item3.Count) { break; } object obj = item3[num]; if (item4.Contains(obj.ToString())) { item3.RemoveAt(num); object item2 = item3[num]; item3.RemoveAt(num); item3[--num] = new List<object> { item, obj, item2 }; } } } } } private static void IDK2(List<string> Stack, List<object> Parent) { bool flag = false; for (int i = 0; i < Parent.Count; i += 2) { object obj = Parent[i]; if (!flag) { if (obj is List<object>) { List<string> list = new List<string>(); IDK2(list, obj as List<object>); foreach (string item in list) { Stack.Add(item); } } else { Stack.Add(obj.ToString()); } flag = true; } object obj2 = Parent.ElementAtOrDefault(i + 1); object obj3 = Parent.ElementAtOrDefault(i + 2); if (obj2 == null) { continue; } if (obj3 is List<object>) { List<string> list2 = new List<string>(); IDK2(list2, obj3 as List<object>); foreach (string item2 in list2) { Stack.Add(item2); } } else { Stack.Add(obj3.ToString()); } Stack.Add(obj2.ToString()); } } public static List<string> Convert(string Value) { UtilsMod.Logger("LU_EQ", (LogLevel)2, (object)("LU_EQ-Convert: " + Value)); Value = Regex.Replace(Value, "\\s", ""); Value = Regex.Replace(Value, "([\\)])([\\(])", "$1*$2"); Value = Regex.Replace(Value, "([^\\+\\-\\*\\/\\^][\\(\\)])(\\d*x)", "$1*$2"); Value = Regex.Replace(Value, "(\\d*x)([\\(\\)][^\\+\\-\\*\\/\\^])", "$1*$2"); Value = Regex.Replace(Value, "(\\d+)(x)", "$1*$2"); Value = Regex.Replace(Value, "(x)(\\d+)", "$1*$2"); UtilsMod.Logger("LU_EQ", (LogLevel)2, (object)("LU_EQ-Convert: " + Value)); List<string> list = new List<string>(); List<object> list2 = new List<object>(); Match match = Regex.Match(Value, "(\\-?[\\dx\\.]+)", RegexOptions.Multiline); Match match2 = Regex.Match(Value, "([\\+\\-\\*\\/\\^\\%])(\\-?[\\dx\\.]+)", RegexOptions.Multiline); Match match3 = match; for (int i = 0; i < Value.Length; i++) { char c = Value[i]; switch (c) { case '(': { List<object> list3 = new List<object> { list2 }; list2.Add(list3); list2 = list3; continue; } case ')': { List<object> list4 = list2; list2 = (List<object>)list4[0]; list4.RemoveAt(0); if (list4.Count == 1) { List<object> list5 = list2; list5[list5.Count - 1] = list4[0]; } continue; } } string text = match3.Groups.ElementAtOrDefault<Group>(1)?.Value; string text2 = match3.Groups.ElementAtOrDefault<Group>(2)?.Value; int index = match3.Index; int num = index + match3.Length - 1; if (text != null && i == index) { i = num; list2.Add(text); if (text2 != null) { list2.Add(text2); } match2 = ((match3 == match) ? match2 : match2.NextMatch()); match3 = match2; } else { list2.Add(c); } } IDK(new List<object>(1) { list2 }); IDK2(list, list2); return list; } } } namespace LethalUtilities.Preloader { internal class Plugin { } } namespace LethalUtilities.Configuration { public enum LU_Direction { None, DictionaryKey, DictionaryValue } public enum NetworkedConfigSync { Unspecified, HostOnly, ClientOnly, SyncWithHost } public enum LoadSettings { ApplyConfig, OnlyLoadSettings, Disabled } public class ConfigUtilities { public enum TypeConverterEnum { Unknown, Variable, List, Dictionary } public class TypeConverterBase { public Type KeyType; public Type ValueType; public Func<object, Type, Type, string> ConvertToString; public Func<string, Type, Type, object> ConvertToObject; public Func<object, object> ConvertToHash; public Func<Type, Type, object> GetDefaultValue; public TypeConverterEnum TypeEnum = TypeConverterEnum.Unknown; } public class DictTypeConverter<KeyT, ValueT> : TypeConverterBase { public Func<object, Type, Type, string> ConvertToString_Default = delegate(object input, Type keyType, Type valueType) { Dictionary<string, string> dictionary2 = new Dictionary<string, string>(); foreach (KeyValuePair<KeyT, ValueT> item in input as Dictionary<KeyT, ValueT>) { dictionary2.TryAdd(TomlTypeConverter.ConvertToString((object)item.Key, keyType), TomlTypeConverter.ConvertToString((object)item.Value, valueType)); } return JsonConvert.SerializeObject((object)dictionary2); }; public Func<string, Type, Type, object> ConvertToObject_Default = delegate(string input, Type keyType, Type valueType) { Dictionary<KeyT, ValueT> dictionary = new Dictionary<KeyT, ValueT>(); foreach (KeyValuePair<string, string> item2 in JsonConvert.DeserializeObject<Dictionary<string, string>>(input)) { dictionary.TryAdd((KeyT)TomlTypeConverter.ConvertToValue(item2.Key, keyType), (ValueT)TomlTypeConverter.ConvertToValue(item2.Value, valueType)); } return dictionary; }; public Func<object, object> ConvertToHash_Default = (object input) => ((Dictionary<KeyT, ValueT>)input).ToDictionary((KeyValuePair<KeyT, ValueT> x) => x.Key.GetHashCode(), (KeyValuePair<KeyT, ValueT> x) => x.Value); public ValueT GetValueFromKey(Dictionary<KeyT, ValueT> Dict, KeyT Key) { return Dict.GetValueOrDefault(Key); } public ValueT GetValueFromKey(object Dict, KeyT Key) { return GetValueFromKey((Dictionary<KeyT, ValueT>)Dict, Key); } public DictTypeConverter(Func<object, Type, Type, string> ConvertToString = null, Func<string, Type, Type, object> ConvertToObject = null, Func<Type, Type, object> GetDefaultValue = null) { KeyType = typeof(KeyT); ValueType = typeof(ValueT); base.ConvertToString = ConvertToString ?? ConvertToString_Default; base.ConvertToObject = ConvertToObject ?? ConvertToObject_Default; base.GetDefaultValue = GetDefaultValue; ConvertToHash = ConvertToHash_Default; TypeEnum = TypeConverterEnum.Dictionary; } } public class ListTypeConverter<ValueT> : TypeConverterBase { public Func<object, Type, Type, string> ConvertToString_Default = (object input, Type keyType, Type valueType) => JsonConvert.SerializeObject((object)(input as List<ValueT>).Select((ValueT E) => TomlTypeConverter.ConvertToString((object)E, valueType))); public Func<string, Type, Type, object> ConvertToObject_Default = (string input, Type keyType, Type valueType) => from E in JsonConvert.DeserializeObject<List<string>>(input) select (ValueT)TomlTypeConverter.ConvertToValue(E, valueType); public ListTypeConverter(Func<object, Type, Type, string> ConvertToString = null, Func<string, Type, Type, object> ConvertToObject = null, Func<Type, Type, object> GetDefaultValue = null) { ValueType = typeof(ValueT); base.ConvertToString = ConvertToString ?? ConvertToString_Default; base.ConvertToObject = ConvertToObject ?? ConvertToObject_Default; base.GetDefaultValue = GetDefaultValue; TypeEnum = TypeConverterEnum.List; } } public class TypeConverter<T> : TypeConverterBase { public Func<object, Type, Type, string> ConvertToString_Default = (object input, Type keyType, Type valueType) => TomlTypeConverter.ConvertToString(input, keyType); public Func<string, Type, Type, object> ConvertToObject_Default = (string input, Type keyType, Type valueType) => (T)TomlTypeConverter.ConvertToValue(input, keyType); public TypeConverter(Func<object, Type, Type, string> ConvertToString = null, Func<string, Type, Type, object> ConvertToObject = null, Func<Type, Type, object> GetDefaultValue = null) { KeyType = typeof(T); base.ConvertToString = ConvertToString ?? ConvertToString_Default; base.ConvertToObject = ConvertToObject ?? ConvertToObject_Default; base.GetDefaultValue = GetDefaultValue; TypeEnum = TypeConverterEnum.Variable; } } public static bool AddedTypes = false; public static List<TypeConverterBase> CustomDictTypeConverters = new List<TypeConverterBase>(9) { new DictTypeConverter<Enum, LU_EQ>(delegate(object input, Type keyType, Type valueType) { Dictionary<string, string> dictionary10 = new Dictionary<string, string>(); foreach (KeyValuePair<Enum, LU_EQ> item in input as Dictionary<Enum, LU_EQ>) { dictionary10.TryAdd(item.Key.ToString(), item.Value.Formula); } return JsonConvert.SerializeObject((object)dictionary10); }, delegate(string input, Type keyType, Type valueType) { Dictionary<Enum, LU_EQ> dictionary9 = new Dictionary<Enum, LU_EQ>(); foreach (KeyValuePair<string, string> item2 in JsonConvert.DeserializeObject<Dictionary<string, string>>(input)) { if (Enum.TryParse(keyType, item2.Key, ignoreCase: true, out object result12)) { dictionary9.TryAdd((Enum)result12, new LU_EQ(item2.Value)); } } return dictionary9; }, delegate(Type keyType, Type valueType) { Dictionary<Enum, LU_EQ> dictionary8 = new Dictionary<Enum, LU_EQ>(); foreach (Enum value2 in Enum.GetValues(keyType)) { dictionary8.Add(value2, new LU_EQ()); } return dictionary8; }), new DictTypeConverter<string, LU_EQ>(delegate(object input, Type keyType, Type valueType) { Dictionary<string, string> dictionary7 = new Dictionary<string, string>(); foreach (KeyValuePair<string, LU_EQ> item3 in input as Dictionary<string, LU_EQ>) { dictionary7.TryAdd(item3.Key, item3.Value?.Formula); } return JsonConvert.SerializeObject((object)dictionary7); }, delegate(string input, Type keyType, Type valueType) { Dictionary<string, LU_EQ> dictionary6 = new Dictionary<string, LU_EQ>(); foreach (KeyValuePair<string, string> item4 in JsonConvert.DeserializeObject<Dictionary<string, string>>(input)) { dictionary6.TryAdd(item4.Key, new LU_EQ(item4.Value)); } return dictionary6; }, (Type keyType, Type valueType) => new Dictionary<string, LU_EQ>()), new DictTypeConverter<string, List<string>>(), new DictTypeConverter<string, string>(null, null, (Type keyType, Type valueType) => new Dictionary<string, LU_EQ>()), new ListTypeConverter<string>((object input, Type keyType, Type valueType) => JsonConvert.SerializeObject((object)(input as List<string>)), (string input, Type keyType, Type valueType) => JsonConvert.DeserializeObject<List<string>>(input), (Type keyType, Type valueType) => new List<string>()), new TypeConverter<Enum>((object input, Type keyType, Type valueType) => input.ToString(), (string input, Type keyType, Type valueType) => Enum.TryParse(valueType, input, out object result11) ? result11 : null), new TypeConverter<string>(), new TypeConverter<bool>((object input, Type keyType, Type valueType) => input.ToString(), (string input, Type keyType, Type valueType) => bool.TryParse(input, out var result10) ? ((object)result10) : null, (Type keyType, Type valueType) => null), new TypeConverter<LU_EQ>((object input, Type keyType, Type valueType) => ((LU_EQ)input).Formula, (string input, Type keyType, Type valueType) => new LU_EQ(input), (Type keyType, Type valueType) => new LU_EQ()) }; public static readonly Dictionary<Type, TypeConverter> CustomTypeConverters = new Dictionary<Type, TypeConverter> { [typeof(Dictionary<string, List<string>>)] = new TypeConverter { ConvertToObject = (string input, Type type) => JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(input), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject(input) }, [typeof(Dictionary<string, string>)] = new TypeConverter { ConvertToObject = (string input, Type type) => JsonConvert.DeserializeObject<Dictionary<string, string>>(input), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject(input) }, [typeof(List<string>)] = new TypeConverter { ConvertToObject = (string input, Type type) => JsonConvert.DeserializeObject<List<string>>(input), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject(input) }, [typeof(LU_EQ)] = new TypeConverter { ConvertToObject = (string input, Type type) => new LU_EQ(input), ConvertToString = (object input, Type type) => ((LU_EQ)input).Formula }, [typeof(AnimationCurve)] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Expected O, but got Unknown //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) if (type != typeof(AnimationCurve)) { return (object)new AnimationCurve(); } string[] array4 = Regex.Replace(input, "[\\s%()%[\\]]+", "").Split(','); if (string.IsNullOrEmpty(array4[0])) { return (object)new AnimationCurve(); } Keyframe[] array5 = (Keyframe[])(object)new Keyframe[array4.Length]; Keyframe val11 = default(Keyframe); for (int l = 0; l < array5.Length; l++) { string[] array6 = array4[l].Split(';'); string[] array7 = ((array6 != null && array6.Length >= 1) ? ((array6 != null) ? array6[0]?.Split(':') : null) : null); string[] array8 = ((array6 != null && array6.Length >= 2) ? ((array6 != null) ? array6[1]?.Split('|') : null) : null); string[] array9 = ((array6 != null && array6.Length >= 3) ? ((array6 != null) ? array6[2]?.Split(':') : null) : null); string[] array10 = ((array9 != null && array9.Length >= 2) ? ((array9 != null) ? array9[1] : null) : ((array9 != null) ? array9[0] : null))?.Split('|'); float result3 = (float.TryParse(((array7 != null) ? array7[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result3) ? result3 : 0f); float result4 = (float.TryParse((array7 != null && array7.Length >= 2) ? ((array7 != null) ? array7[1] : null) : "0", NumberStyles.Float, new CultureInfo("en-US"), out result4) ? result4 : 0f); float result5 = (float.TryParse(((array8 != null) ? array8[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result5) ? result5 : 0f); float result6 = (float.TryParse((array8 != null && array8.Length >= 2) ? ((array8 != null) ? array8[1] : null) : (((array8 != null) ? array8[0] : null) ?? "0"), NumberStyles.Float, new CultureInfo("en-US"), out result6) ? result6 : 0f); float result7 = (float.TryParse(((array10 != null) ? array10[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result7) ? result7 : 0f); float result8 = (float.TryParse((array10 != null && array10.Length >= 2) ? ((array10 != null) ? array10[1] : null) : (((array10 != null) ? array10[0] : null) ?? "0"), NumberStyles.Float, new CultureInfo("en-US"), out result8) ? result8 : 0f); int result9 = (int.TryParse(((array9 != null) ? array9[0] : null) ?? "0", NumberStyles.Float, new CultureInfo("en-US"), out result9) ? result9 : 0); ((Keyframe)(ref val11))..ctor(result3, result4, result5, result6, result7, result8); ((Keyframe)(ref val11)).weightedMode = (WeightedMode)result9; Keyframe val12 = val11; array5[l] = val12; } return (object)new AnimationCurve(array5); }, ConvertToString = delegate(object input, Type type) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected I4, but got Unknown if (type != typeof(AnimationCurve)) { return ""; } Keyframe[] keys = ((AnimationCurve)input).keys; if (keys.Length == 0) { return ""; } if (keys.Length == 1) { return ((Keyframe)(ref keys[0])).value.ToString(new CultureInfo("en-US")); } StringBuilder stringBuilder = new StringBuilder(); Keyframe[] array3 = keys; for (int k = 0; k < array3.Length; k++) { Keyframe val10 = array3[k]; float time = ((Keyframe)(ref val10)).time; float value = ((Keyframe)(ref val10)).value; float inTangent = ((Keyframe)(ref val10)).inTangent; float outTangent = ((Keyframe)(ref val10)).outTangent; float inWeight = ((Keyframe)(ref val10)).inWeight; float outWeight = ((Keyframe)(ref val10)).outWeight; int num2 = (int)((Keyframe)(ref val10)).weightedMode; stringBuilder.Append(time.ToString(new CultureInfo("en-US")) + ":" + value.ToString(new CultureInfo("en-US"))); if (inTangent != 0f || outTangent != 0f) { stringBuilder.Append((inTangent == outTangent) ? $";({inTangent})" : $";({inTangent}|{outTangent})"); if (inWeight != 0f || outWeight != 0f) { stringBuilder.Append((num2 != 0) ? (";" + num2.ToString(new CultureInfo("en-US")) + ":") : ";"); stringBuilder.Append((inWeight == outWeight) ? ("[" + inWeight.ToString(new CultureInfo("en-US")) + "]") : ("[" + inWeight.ToString(new CultureInfo("en-US")) + "|" + outWeight.ToString(new CultureInfo("en-US")) + "]")); } else if (num2 != 0) { stringBuilder.Append(";" + num2.ToString(new CultureInfo("en-US"))); } } stringBuilder.Append(", "); } return stringBuilder.ToString(0, Math.Max(0, stringBuilder.Length - 2)); } }, [typeof(string[])] = SimpleConverter(new string[0]), [typeof(Battery)] = SimpleConverter<Battery>(new Battery(false, 1f)), [typeof(IntWithRarity[])] = new TypeConverter { ConvertToObject = (string input, Type type) => ((IEnumerable<KeyValuePair<int, int>>)JsonConvert.DeserializeObject<Dictionary<int, int>>(input)).Select((Func<KeyValuePair<int, int>, IntWithRarity>)((KeyValuePair<int, int> x) => new IntWithRarity { id = x.Key, rarity = x.Value })).ToArray(), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject((object)((IntWithRarity[])input).Select((IntWithRarity x) => new KeyValuePair<int, int>(x.id, x.rarity)).ToDictionary((KeyValuePair<int, int> x) => x.Key, (KeyValuePair<int, int> x) => x.Value)) }, [typeof(CompatibleNoun[])] = new TypeConverter { ConvertToObject = (string input, Type type) => ((IEnumerable<KeyValuePair<string, string>>)JsonConvert.DeserializeObject<Dictionary<string, string>>(input)).Select((Func<KeyValuePair<string, string>, CompatibleNoun>)((KeyValuePair<string, string> PAIR) => new CompatibleNoun { noun = ((IEnumerable<TerminalKeyword>)Resources.FindObjectsOfTypeAll<TerminalKeyword>()).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword X) => MakeFileNameSafe(((Object)X).name) == PAIR.Key)), result = ((IEnumerable<TerminalNode>)Resources.FindObjectsOfTypeAll<TerminalNode>()).FirstOrDefault((Func<TerminalNode, bool>)((TerminalNode X) => MakeFileNameSafe(((Object)X).name) == PAIR.Value)) })).ToArray(), ConvertToString = delegate(object input, Type type) { Dictionary<string, string> NewOptions = new Dictionary<string, string>(); IEnumerable<CompatibleNoun> enumerable = ((CompatibleNoun[])input).Where((CompatibleNoun x) => (Object)(object)x.noun != (Object)null && !NewOptions.ContainsKey(((Object)x.noun).name)); foreach (CompatibleNoun item5 in enumerable) { Dictionary<string, string> dictionary5 = NewOptions; string name = ((Object)item5.noun).name; TerminalNode result2 = item5.result; dictionary5.Add(name, ((result2 != null) ? ((Object)result2).name : null) ?? ""); } return JsonConvert.SerializeObject((object)NewOptions); } }, [typeof(TerminalKeyword)] = new TypeConverter { ConvertToObject = (string input, Type type) => ((IEnumerable<TerminalKeyword>)Resources.FindObjectsOfTypeAll<TerminalKeyword>()).FirstOrDefault((Func<TerminalKeyword, bool>)((TerminalKeyword X) => MakeFileNameSafe(((Object)X).name) == input)), ConvertToString = (object input, Type type) => ((Object)(TerminalKeyword)input).name }, [typeof(TerminalNode)] = new TypeConverter { ConvertToObject = (string input, Type type) => ((IEnumerable<TerminalNode>)Resources.FindObjectsOfTypeAll<TerminalNode>()).FirstOrDefault((Func<TerminalNode, bool>)((TerminalNode X) => MakeFileNameSafe(((Object)X).name) == input)), ConvertToString = (object input, Type type) => ((Object)(TerminalNode)input).name }, [typeof(SpawnableEnemyWithRarity[])] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown List<SpawnableEnemyWithRarity> list5 = new List<SpawnableEnemyWithRarity>(); foreach (KeyValuePair<string, int> PAIR5 in JsonConvert.DeserializeObject<Dictionary<string, int>>(input)) { EnemyType val9 = ((IEnumerable<EnemyType>)Resources.FindObjectsOfTypeAll<EnemyType>()).FirstOrDefault((Func<EnemyType, bool>)((EnemyType X) => MakeFileNameSafe(X.enemyName) == PAIR5.Key)); if (!((Object)(object)val9 == (Object)null) && !((Object)(object)val9 == (Object)null)) { list5.Add(new SpawnableEnemyWithRarity { enemyType = val9, rarity = PAIR5.Value }); } } return list5.ToArray(); }, ConvertToString = delegate(object input, Type type) { Dictionary<string, int> dictionary4 = new Dictionary<string, int>(); SpawnableEnemyWithRarity[] array2 = (SpawnableEnemyWithRarity[])input; foreach (SpawnableEnemyWithRarity val8 in array2) { string text4 = val8.enemyType?.enemyName; if (text4 != null && text4 != null) { if (dictionary4.ContainsKey(text4)) { dictionary4[text4] += val8.rarity; } else { dictionary4.Add(text4, val8.rarity); } } } return JsonConvert.SerializeObject((object)dictionary4); } }, [typeof(SpawnableItemWithRarity[])] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown List<SpawnableItemWithRarity> list4 = new List<SpawnableItemWithRarity>(); foreach (KeyValuePair<string, int> PAIR4 in JsonConvert.DeserializeObject<Dictionary<string, int>>(input)) { Item val7 = ((IEnumerable<Item>)Resources.FindObjectsOfTypeAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item X) => MakeFileNameSafe(X.itemName) == PAIR4.Key)); if (!((Object)(object)val7 == (Object)null) && !((Object)(object)val7 == (Object)null)) { list4.Add(new SpawnableItemWithRarity { spawnableItem = val7, rarity = PAIR4.Value }); } } return list4.ToArray(); }, ConvertToString = delegate(object input, Type type) { Dictionary<string, int> dictionary3 = new Dictionary<string, int>(); SpawnableItemWithRarity[] array = (SpawnableItemWithRarity[])input; foreach (SpawnableItemWithRarity val6 in array) { string text3 = val6.spawnableItem?.itemName; if (text3 != null && text3 != null) { if (dictionary3.ContainsKey(text3)) { dictionary3[text3] += val6.rarity; } else { dictionary3.Add(text3, val6.rarity); } } } return JsonConvert.SerializeObject((object)dictionary3); } }, [typeof(List<SpawnableEnemyWithRarity>)] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown List<SpawnableEnemyWithRarity> list3 = new List<SpawnableEnemyWithRarity>(); foreach (KeyValuePair<string, int> PAIR3 in JsonConvert.DeserializeObject<Dictionary<string, int>>(input)) { EnemyType val5 = ((IEnumerable<EnemyType>)Resources.FindObjectsOfTypeAll<EnemyType>()).FirstOrDefault((Func<EnemyType, bool>)((EnemyType X) => MakeFileNameSafe(X.enemyName) == PAIR3.Key)); if (!((Object)(object)val5 == (Object)null) && !((Object)(object)val5 == (Object)null)) { list3.Add(new SpawnableEnemyWithRarity { enemyType = val5, rarity = PAIR3.Value }); } } return list3; }, ConvertToString = delegate(object input, Type type) { Dictionary<string, int> dictionary2 = new Dictionary<string, int>(); foreach (SpawnableEnemyWithRarity item6 in (List<SpawnableEnemyWithRarity>)input) { string text2 = item6.enemyType?.enemyName; if (text2 != null && text2 != null) { if (dictionary2.ContainsKey(text2)) { dictionary2[text2] += item6.rarity; } else { dictionary2.Add(text2, item6.rarity); } } } return JsonConvert.SerializeObject((object)dictionary2); } }, [typeof(List<SpawnableItemWithRarity>)] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown List<SpawnableItemWithRarity> list2 = new List<SpawnableItemWithRarity>(); foreach (KeyValuePair<string, int> PAIR2 in JsonConvert.DeserializeObject<Dictionary<string, int>>(input)) { Item val4 = ((IEnumerable<Item>)Resources.FindObjectsOfTypeAll<Item>()).FirstOrDefault((Func<Item, bool>)((Item X) => MakeFileNameSafe(X.itemName) == PAIR2.Key)); if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4 == (Object)null)) { list2.Add(new SpawnableItemWithRarity { spawnableItem = val4, rarity = PAIR2.Value }); } } return list2; }, ConvertToString = delegate(object input, Type type) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (SpawnableItemWithRarity item7 in (List<SpawnableItemWithRarity>)input) { string text = item7.spawnableItem?.itemName; if (text != null && text != null) { if (dictionary.ContainsKey(text)) { dictionary[text] += item7.rarity; } else { dictionary.Add(text, item7.rarity); } } } return JsonConvert.SerializeObject((object)dictionary); } }, [typeof(EnemyType)] = new TypeConverter { ConvertToObject = (string input, Type type) => ((IEnumerable<EnemyType>)Resources.FindObjectsOfTypeAll<EnemyType>()).FirstOrDefault((Func<EnemyType, bool>)((EnemyType X) => MakeFileNameSafe(X.enemyName) == input)), ConvertToString = (object input, Type type) => ((EnemyType)input).enemyName }, [typeof(List<ItemGroup>)] = new TypeConverter { ConvertToObject = delegate(string input, Type type) { List<ItemGroup> list = new List<ItemGroup>(); foreach (string item8 in JsonConvert.DeserializeObject<List<string>>(input)) { ItemGroup val3 = ScriptableObject.CreateInstance<ItemGroup>(); ((Object)val3).name = item8; list.Add(val3); } return list; }, ConvertToString = (object input, Type type) => JsonConvert.SerializeObject((object)((List<ItemGroup>)input).Select((ItemGroup x) => ((Object)x).name).ToList()) }, [typeof(RandomWeatherWithVariables[])] = new TypeConverter { ConvertToObject = (string input, Type type) => JsonConvert.DeserializeObject<Dictionary<string, List<int>>>(input).Select(delegate(KeyValuePair<string, List<int>> PAIR) { //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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got I4 ? val = new RandomWeatherWithVariables(); ? val2 = val; int num; if (!Enum.TryParse<LevelWeatherType>(PAIR.Key, out LevelWeatherType result)) { num = -1; val = num; num = (int)val; } else { val = result; num = (int)val; } ((RandomWeatherWithVariables)val2).weatherType = (LevelWeatherType)val; ((RandomWeatherWithVariables)num).weatherVariable = ((PAIR.Value.Count > 0) ? PAIR.Value[0] : 0); ((RandomWeatherWithVariables)num).weatherVariable2 = ((PAIR.Value.Count > 1) ? PAIR.Value[1] : 0); return (RandomWeatherWithVariables)(object)num; }).ToArray(), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject((object)((RandomWeatherWithVariables[])input).Select((RandomWeatherWithVariables x) => new KeyValuePair<string, List<int>>(((object)(LevelWeatherType)(ref x.weatherType)).ToString(), new List<int>(2) { x.weatherVariable, x.weatherVariable2 })).ToDictionary((KeyValuePair<string, List<int>> x) => x.Key, (KeyValuePair<string, List<int>> x) => x.Value)) } }; public static bool AddAllTypes() { if (AddedTypes) { return false; } AddedTypes = true; foreach (KeyValuePair<Type, TypeConverter> customTypeConverter in CustomTypeConverters) { TomlTypeConverter.AddConverter(customTypeConverter.Key, customTypeConverter.Value); } return true; } public static string MakeFileNameSafe(string FileName) { return Regex.Replace(FileName, "[\\/:*?\"<>|]", ""); } public static TypeConverter SimpleConverter<T>(T Default) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown return new TypeConverter { ConvertToObject = (string input, Type type) => (type != typeof(T)) ? Default : JsonConvert.DeserializeObject<T>(input), ConvertToString = (object input, Type type) => JsonConvert.SerializeObject((type != typeof(T)) ? ((object)Default) : input) }; } } public sealed class SettingChangedEventArgs : EventArgs { public ConfigEntryBase ChangedSetting { get; } public SettingChangedEventArgs(ConfigEntryBase changedSetting) { ChangedSetting = changedSetting; base..ctor(); } } public class ConfigEntrySettings { private static readonly char[] _invalidConfigChars = new char[8] { '=', '\n', '\t', '\\', '"', '\'', '[', ']' }; public ConfigEntryBase Config; public int SectionOrder; private readonly string _StringValue; public string Description; public NetworkedConfigSync SyncType; public Type KeyType; public Type ValueType; public List<object> UsedKeys; public List<string> AcceptableKeys; public AcceptableValueBase AcceptableValues; public bool IncludeAccessedKeys; public LU_Direction Rule; public string Section { get; } public string Key { get; } public string StringValue => Config?.GetSerializedValue() ?? _StringValue; public ConfigEntrySettings(ConfigEntryBase Config, string Section, string Key, string StringValue = null, int SectionOrder = -1) { this.Config = Config; this.Section = (CheckInvalidConfigChars(Section, "Section") ? Section : null); this.SectionOrder = SectionOrder; this.Key = (CheckInvalidConfigChars(Key, "Key") ? Key : null); _StringValue = StringValue; UsedKeys = new List<object>(); AcceptableKeys = new List<string>(); IncludeAccessedKeys = false; Rule = LU_Direction.None; base..ctor(); } public ConfigUtilities.TypeConverterBase GetConverter() { foreach (ConfigUtilities.TypeConverterBase customDictTypeConverter in ConfigUtilities.CustomDictTypeConverters) { if (customDictTypeConverter.TypeEnum == ConfigUtilities.TypeConverterEnum.Variable && Rule == LU_Direction.None) { Type keyType = customDictTypeConverter.KeyType; if ((object)keyType != null && keyType.IsAssignableFrom(ValueType)) { return customDictTypeConverter; } } else if (customDictTypeConverter.TypeEnum == ConfigUtilities.TypeConverterEnum.Dictionary && Rule == LU_Direction.DictionaryKey) { Type keyType2 = customDictTypeConverter.KeyType; if ((object)keyType2 != null && keyType2.IsAssignableFrom(KeyType)) { Type valueType = customDictTypeConverter.ValueType; if ((object)valueType != null && valueType.IsAssignableFrom(ValueType)) { return customDictTypeConverter; } } } else if (customDictTypeConverter.TypeEnum == ConfigUtilities.TypeConverterEnum.List && Rule == LU_Direction.DictionaryValue) { Type valueType2 = customDictTypeConverter.ValueType; if ((object)valueType2 != null && valueType2.IsAssignableFrom(ValueType)) { return customDictTypeConverter; } } } return null; } private static bool CheckInvalidConfigChars(string val, string name) { if (val == null) { throw new ArgumentNullException(name); } if (val != val.Trim()) { throw new ArgumentException("Cannot use whitespace characters at start or end of section and key names", name); } if (val.Any((char c) => _invalidConfigChars.Contains(c))) { throw new ArgumentException("Cannot use any of the following characters in section and key names: = \\n \\t \\ \" ' [ ]", name); } return true; } } public abstract class AcceptableValueBase { public Type ValueType { get; } protected AcceptableValueBase(Type ValueType) { this.ValueType = ValueType; base..ctor(); } public abstract object Clamp(object value); public abstract bool IsValid(object value); public abstract string ToDescriptionString(); } public class AcceptableValueList<T> : AcceptableValueBase where T : IEquatable<T> { public virtual T[] AcceptableValues { get; } public AcceptableValueList(params T[] AcceptableValues) { if (AcceptableValues == null) { throw new ArgumentNullException("AcceptableValues"); } if (AcceptableValues.Length == 0) { throw new ArgumentException("At least one acceptable value is needed", "AcceptableValues"); } this.AcceptableValues = AcceptableValues; base..ctor(typeof(T)); } public override object Clamp(object value) { return IsValid(value) ? value : ((object)AcceptableValues[0]); } public override bool IsValid(object value) { int result; if (value is T) { T v = (T)value; result = (AcceptableValues.Any((T x) => x.Equals(v)) ? 1 : 0); } else { result = 0; } return (byte)result != 0; } public override string ToDescriptionString() { return "# Acceptable values: " + string.Join(", ", AcceptableValues.Select((T x) => x.ToString())); } } public class AcceptableValueRange<T> : AcceptableValueBase where T : IComparable { public virtual T MinValue { get; } public virtual T MaxValue { get; } public AcceptableValueRange(T MinValue, T MaxValue) { T val = MinValue; if (val == null) { throw new ArgumentNullException("MinValue"); } this.MinValue = val; if (MaxValue == null) { throw new ArgumentNullException("MaxValue"); } if (MinValue.CompareTo(MaxValue) >= 0) { throw new ArgumentNullException("MinValue has to be lower than MaxValue"); } this.MaxValue = MaxValue; base..ctor(typeof(T)); } public override object Clamp(object value) { return (MinValue.CompareTo(value) > 0) ? ((object)MinValue) : ((MaxValue.CompareTo(value) < 0) ? ((object)MaxValue) : value); } public override bool IsValid(object value) { return MinValue.CompareTo(value) <= 0 && MaxValue.CompareTo(value) >= 0; } public override string ToDescriptionString() { return $"# Acceptable value range: From {MinValue} to {MaxValue}"; } } public abstract class ConfigEntryBase { public object DefaultValue; public object HashValue; public string RawValue; public ConfigFile ConfigFile { get; } public ConfigEntrySettings EntrySettings { get; set; } public abstract object BoxedValue { get; set; } internal ConfigEntryBase(ConfigFile configFile, ConfigEntrySettings entrySettings, object defaultValue, string rawValue = null) { entrySettings.Config = this; ConfigFile = configFile ?? throw new ArgumentNullException("configFile"); EntrySettings = entrySettings ?? throw new ArgumentNullException("entrySettings"); DefaultValue = defaultValue; RawValue = rawValue; BoxedValue = defaultValue; } public string GetSerializedValue() { return (EntrySettings.GetConverter() ?? throw new InvalidOperationException("Cannot convert from type " + ((EntrySettings.KeyType != null && EntrySettings.ValueType != null) ? $"Dictionary<{EntrySettings.KeyType}, {EntrySettings.ValueType}>" : ((EntrySettings.ValueType != null) ? $"List<{EntrySettings.ValueType}>" : $"{EntrySettings.KeyType}")))).ConvertToString(BoxedValue, EntrySettings.KeyType, EntrySettings.ValueType); } public void SetSerializedValue(string value) { try { ConfigUtilities.TypeConverterBase typeConverterBase = EntrySettings.GetConverter() ?? throw new InvalidOperationException("Cannot convert to type " + ((EntrySettings.KeyType != null && EntrySettings.ValueType != null) ? $"Dictionary<{EntrySettings.KeyType}, {EntrySettings.ValueType}>" : ((EntrySettings.ValueType != null) ? $"List<{EntrySettings.ValueType}>" : $"{EntrySettings.KeyType}"))); BoxedValue = typeConverterBase.ConvertToObject(value, EntrySettings.KeyType, EntrySettings.ValueType); } catch (Exception ex) { UtilsMod.MLS.Log((LogLevel)4, (object)("Config value of setting \"" + EntrySettings.Section + "." + EntrySettings.Key + "\" could not be parsed and will be ignored. Reason: " + ex.Message + "; Value: " + value)); } } protected T ClampValue<T>(T value) { return (EntrySettings.AcceptableValues != null) ? ((T)EntrySettings.AcceptableValues.Clamp(value)) : value; } protected void OnSettingChanged(object sender) { ConfigFile.OnSettingChanged(sender, this); } public string FixTypeName(Type Fix) { return (Fix == null) ? "null" : ((typeof(List<>).Name == Fix.Name) ? ("List<" + FixTypeName(Fix.GenericTypeArguments.ElementAtOrDefault(0)) + ">") : ((typeof(Dictionary<, >).Name == Fix.Name) ? ("Dictionary<" + FixTypeName(Fix.GenericTypeArguments.ElementAtOrDefault(0)) + ", " + FixTypeName(Fix.GenericTypeArguments.ElementAtOrDefault(1)) + ">") : Fix.Name)); } public void WriteDescription(StreamWriter writer) { if (!string.IsNullOrEmpty(EntrySettings.Description)) { writer.WriteLine("## " + EntrySettings.Description.Replace("\n", "\n## ")); } writer.WriteLine("# Setting type: " + ((EntrySettings.Rule == LU_Direction.DictionaryKey) ? ("Dictionary<" + FixTypeName(EntrySettings.KeyType) + ", " + FixTypeName(EntrySettings.ValueType) + ">") : ((EntrySettings.Rule == LU_Direction.DictionaryValue) ? ("List<" + FixTypeName(EntrySettings.ValueType) + ">") : FixTypeName(EntrySettings.ValueType)))); writer.WriteLine("# Sync type: " + EntrySettings.SyncType); if (RawValue != null) { writer.WriteLine("# Raw value: " + RawValue); } bool flag = EntrySettings.IncludeAccessedKeys; if (EntrySettings.AcceptableKeys != null && EntrySettings.AcceptableKeys.Count > 0) { writer.WriteLine("# Acceptable keys: " + string.Join(", ", EntrySettings.AcceptableKeys)); } else if (EntrySettings.KeyType != null && EntrySettings.KeyType.IsEnum) { writer.WriteLine("# Acceptable keys: " + string.Join(", ", Enum.GetNames(EntrySettings.KeyType))); } else if (EntrySettings.UsedKeys != null && EntrySettings.UsedKeys.Count > 0) { flag = true; } if (flag) { writer.WriteLine("# Accessed keys: " + string.Join(", ", EntrySettings.UsedKeys)); } if (EntrySettings.AcceptableValues != null) { writer.WriteLine(EntrySettings.AcceptableValues.ToDescriptionString()); } else if (EntrySettings.ValueType == null || !EntrySettings.ValueType.IsEnum) { return; } writer.WriteLine("# Acceptable values: " + string.Join(", ", Enum.GetNames(EntrySettings.ValueType))); if (EntrySettings.ValueType.GetCustomAttributes(typeof(FlagsAttribute), inherit: true).Any()) { writer.WriteLine("# Multiple values can be set at the same time by separating them with , (e.g. Debug, Warning)"); } } } public sealed class ConfigEntry<T> : ConfigEntryBase { private T _typedValue; public T Value { get { return _typedValue; } set { if (!object.Equals(_typedValue, value = ClampValue(value))) { _typedValue = value; OnSettingChanged(this); } } } public override object BoxedValue { get { return Value; } set { Value = (T)value; } } public event EventHandler SettingChanged; internal ConfigEntry(ConfigFile configFile, ConfigEntrySettings entrySettings, object defaultValue, string RawValue = "") : base(configFile, entrySettings, defaultValue, RawValue) { configFile.SettingChanged += delegate(object sender, SettingChangedEventArgs args) { if (args.ChangedSetting == this) { this.SettingChanged?.Invoke(sender, args); } }; } } public class ConfigFile { public ConfigEntry<LoadSettings> ConfigEnabledVar; public ConfigEntry<List<string>> LoadSettingsVar; private readonly BepInPlugin _ownerMetadata; private readonly object _ioLock = new object(); protected Dictionary<string, ConfigEntryBase> Entries { get; } = new Dictionary<string, ConfigEntryBase>(); private Dictionary<string, ConfigEntrySettings> OrphanedEntries { get; } = new Dictionary<string, ConfigEntrySettings>(); public string ConfigFilePath { get; } public bool SaveOnConfigSet { get; set; } = true; public event EventHandler ConfigReloaded; public event EventHandler<SettingChangedEventArgs> SettingChanged; public ConfigFile(string configPath, bool saveOnInit, BepInPlugin ownerMetadata = null) { _ownerMetadata = ownerMetadata; if (configPath == null) { throw new ArgumentNullException("configPath"); } configPath = Path.GetFullPath(configPath); ConfigFilePath = configPath; if (File.Exists(ConfigFilePath)) { Reload(); } else if (saveOnInit) { Save(); } } public void Reload() { lock (_ioLock) { OrphanedEntries.Clear(); string text = string.Empty; string[] array = File.ReadAllLines(ConfigFilePath); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("#")) { continue; } if (text3.StartsWith("[") && text3.EndsWith("]")) { string text4 = text3; text = text4.Substring(1, text4.Length - 1 - 1); continue; } string[] array2 = text3.Split(new char[1] { '=' }, 2); if (array2.Length == 2) { string text5 = array2[0].Trim(); string text6 = array2[1].Trim(); string key = text + "." + text5; Entries.TryGetValue(key, out var value); if (value != null) { value.SetSerializedValue(text6); } else { OrphanedEntries[key] = new ConfigEntrySettings(null, text, text5, text6); } } } } OnConfigReloaded(); } public void Save() { lock (_ioLock) { string directoryName = Path.GetDirectoryName(ConfigFilePath); if (directoryName != null) { Directory.CreateDirectory(directoryName); } using StreamWriter streamWriter = new StreamWriter(ConfigFilePath, append: false, Utility.UTF8NoBom); if (_ownerMetadata != null) { streamWriter.WriteLine($"## Settings file was created by plugin {_ownerMetadata.Name} v{_ownerMetadata.Version}"); streamWriter.WriteLine("## Plugin GUID: " + _ownerMetadata.GUID); streamWriter.WriteLine(); } foreach (IGrouping<(int, string), ConfigEntrySettings> item in from x in Entries.Select((KeyValuePair<string, ConfigEntryBase> x) => x.Value.EntrySettings).Concat(OrphanedEntries.Select((KeyValuePair<string, ConfigEntrySettings> x) => x.Value)) group x by (x.SectionOrder, x.Section) into x orderby x.Key.SectionOrder == -1, x.Key.SectionOrder, x.Key.Section select x) { streamWriter.WriteLine("[" + item.Key.Item2 + "]"); foreach (ConfigEntrySettings item2 in item) { streamWriter.WriteLine(); item2.Config?.WriteDescription(streamWriter); streamWriter.WriteLine(item2.Key + " = " + item2.StringValue); } streamWriter.WriteLine(); } } } public ConfigEntry<T> Bind<T>(ConfigEntrySettings entrySettings, T defaultValue, string RawValue = null) { lock (_ioLock) { string key = entrySettings.Section + "." + entrySettings.Key; if (Entries.TryGetValue(key, out var value)) { return value as ConfigEntry<T>; } ConfigEntry<T> configEntry = new ConfigEntry<T>(this, entrySettings, defaultValue, RawValue); Entries[key] = configEntry; if (OrphanedEntries.TryGetValue(key, out var value2)) { configEntry.SetSerializedValue(value2.StringValue); OrphanedEntries.Remove(key); } if (SaveOnConfigSet) { Save(); } return configEntry; } } public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string configDescription = null, int order = -1, string RawValue = "", LU_Direction Rule = LU_Direction.None, NetworkedConfigSync SyncType = NetworkedConfigSync.Unspecified) { return Bind(new ConfigEntrySettings(null, section ?? throw new ArgumentNullException("section"), key ?? throw new ArgumentNullException("key")) { ValueType = typeof(T), Description = configDescription, SectionOrder = order, Rule = Rule, SyncType = SyncType }, defaultValue, RawValue); } internal void OnSettingChanged(object sender, ConfigEntryBase changedEntryBase) { if (changedEntryBase == null) { throw new ArgumentNullException("changedEntryBase"); } if (SaveOnConfigSet) { Save(); } if (this.SettingChanged == null) { return; } SettingChangedEventArgs e = new SettingChangedEventArgs(changedEntryBase); foreach (EventHandler<SettingChangedEventArgs> item in this.SettingChanged.GetInvocationList().Cast<EventHandler<SettingChangedEventArgs>>()) { try { item(sender, e); } catch (Exception ex) { UtilsMod.MLS.Log((LogLevel)2, (object)ex); } } } private void OnConfigReloaded() { if (this.ConfigReloaded == null) { return; } foreach (EventHandler item in this.ConfigReloaded.GetInvocationList().Cast<EventHandler>()) { try { item(this, EventArgs.Empty); } catch (Exception ex) { UtilsMod.MLS.Log((LogLevel)2, (object)ex); } } } public bool Remove(string section, string key) { lock (_ioLock) { return Entries.Remove(section + "." + key); } } } } [CompilerGenerated] internal sealed class <>z__ReadOnlySingleElementList<T> : IEnumerable, ICollection, IList, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, ICollection<T>, IList<T> { private sealed class Enumerator : IDisposable, IEnumerator, IEnumerator<T> { object IEnumerator.Current => _item; T IEnumerator<T>.Current => _item; public Enumerator(T item) { _item = item; } bool IEnumerator.MoveNext() { return !_moveNextCalled && (_moveNextCalled = true); } void IEnumerator.Reset() { _moveNextCalled = false; } void IDisposable.Dispose() { } } int ICollection.Count => 1; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection<T>.Count => 1; T IReadOnlyList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } } int ICollection<T>.Count => 1; bool ICollection<T>.IsReadOnly => true; T IList<T>.this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return _item; } set { throw new NotSupportedException(); } } public <>z__ReadOnlySingleElementList(T item) { _item = item; } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(_item); } void ICollection.CopyTo(Array array, int index) { array.SetValue(_item, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return EqualityComparer<T>.Default.Equals(_item, (T)value); } int IList.IndexOf(object value) { return (!EqualityComparer<T>.Default.Equals(_item, (T)value)) ? (-1) : 0; } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return new Enumerator(_item); } void ICollection<T>.Add(T item) { throw new NotSupportedException(); } void ICollection<T>.Clear() { throw new NotSupportedException(); } bool ICollection<T>.Contains(T item) { return EqualityComparer<T>.Default.Equals(_item, item); } void ICollection<T>.CopyTo(T[] array, int arrayIndex) { array[arrayIndex] = _item; } bool ICollection<T>.Remove(T item) { throw new NotSupportedException(); } int IList<T>.IndexOf(T item) { return (!EqualityComparer<T>.Default.Equals(_item, item)) ? (-1) : 0; } void IList<T>.Insert(int index, T item) { throw new NotSupportedException(); } void IList<T>.RemoveAt(int index) { throw new NotSupportedException(); } }