RUMBLE does not support other mod managers. If you want to use a manager, you must use the RUMBLE Mod Manager, a manager specifically designed for this game.
Decompiled source of RumbleModUIPlus v2.0.0
Mods/RumbleModUIPlus.dll
Decompiled a week agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using HarmonyLib; using Il2CppSystem.Collections.Generic; using Il2CppTMPro; using MelonLoader; using RumbleModUI; using RumbleModUIPlus; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(RumbleModUIPlusClass), "RumbleModUIPlus", "2.0.0", "ninjaguardian", "https://thunderstore.io/c/rumble/p/ninjaguardian/RumbleModUIPlus")] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonColor(255, 0, 160, 230)] [assembly: MelonAuthorColor(255, 0, 160, 230)] [assembly: MelonPlatformDomain(/*Could not decode attribute arguments.*/)] [assembly: VerifyLoaderVersion("0.7.1", true)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("ninjaguardian (github)")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © 2025 ninjaguardian (github), This work is dedicated to the public domain under CC0 1.0.")] [assembly: AssemblyDescription("Adds stuff for devs to RumbleModUI (also some bug fixes)")] [assembly: AssemblyFileVersion("2.0.0.0")] [assembly: AssemblyInformationalVersion("2.0.0")] [assembly: AssemblyProduct("RumbleModUIPlus")] [assembly: AssemblyTitle("RumbleModUIPlus")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/ninjaguardian/RumbleModUIPlus")] [assembly: AssemblyVersion("2.0.0.0")] namespace RumbleModUIPlus; public static class BuildInfo { public const string ModName = "RumbleModUIPlus"; public const string ModVersion = "2.0.0"; public const string MLVersion = "0.7.1"; public const string Author = "ninjaguardian"; public const string DownloadLink = "https://thunderstore.io/c/rumble/p/ninjaguardian/RumbleModUIPlus"; } public class Mod : Mod { protected const string DuplicateErrorMsg = "AddToList failed: Name not unique"; private string _modFormatVersion; public string ModFormatVersion { get { return _modFormatVersion ?? ((Mod)this).ModVersion; } set { _modFormatVersion = value; } } public ModSetting<string> AddDescriptionAtStart(string Name, string Value, string Description, Tags tags) { return AddDescriptionAtIndex(Name, Value, Description, tags, 0); } public ModSetting<string> AddDescriptionAtIndex(string Name, string Value, string Description, Tags tags, int Index) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<string> obj = new ModSetting<string> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)0; ModSetting<string> val = obj; tags.DoNotSave = true; ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSetting<string> AddToListAtStart(string Name, string Value, string Description, Tags tags) { return AddToListAtIndex(Name, Value, Description, tags, 0); } public ModSetting<string> AddToListAtIndex(string Name, string Value, string Description, Tags tags, int Index) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<string> obj = new ModSetting<string> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)1; ModSetting<string> val = obj; ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSetting<bool> AddToListAtStart(string Name, bool Value, int LinkGroup, string Description, Tags tags) { return AddToListAtIndex(Name, Value, LinkGroup, Description, tags, 0); } public ModSetting<bool> AddToListAtIndex(string Name, bool Value, int LinkGroup, string Description, Tags tags, int Index) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<bool> obj = new ModSetting<bool> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = LinkGroup; ((ModSetting)obj).ValueType = (AvailableTypes)5; ModSetting<bool> val = obj; if (LinkGroup != 0) { ((Mod)this).SetLinkGroup(LinkGroup, "Group"); base.LinkGroups.Find((LinkGroup x) => x.Index == LinkGroup).Settings.Add((ModSetting)(object)val); } ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSetting<int> AddToListAtStart(string Name, int Value, string Description, Tags tags) { return AddToListAtIndex(Name, Value, Description, tags, 0); } public ModSetting<int> AddToListAtIndex(string Name, int Value, string Description, Tags tags, int Index) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<int> obj = new ModSetting<int> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)2; ModSetting<int> val = obj; ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSetting<float> AddToListAtStart(string Name, float Value, string Description, Tags tags) { return AddToListAtIndex(Name, Value, Description, tags, 0); } public ModSetting<float> AddToListAtIndex(string Name, float Value, string Description, Tags tags, int Index) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<float> obj = new ModSetting<float> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)3; ModSetting<float> val = obj; ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSetting<double> AddToListAtStart(string Name, double Value, string Description, Tags tags) { return AddToListAtIndex(Name, Value, Description, tags, 0); } public ModSetting<double> AddToListAtIndex(string Name, double Value, string Description, Tags tags, int Index) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == Name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + Name); return null; } ModSetting<double> obj = new ModSetting<double> { Name = Name, Description = Description }; ((ModSetting)obj).Value = Value; ((ModSetting)obj).SavedValue = Value; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)4; ModSetting<double> val = obj; ((Mod)this).AddTags((ModSetting)(object)val, tags); if (Index < 0 || Index > base.Settings.Count) { MelonLogger.Error($"Index {Index} is out of bounds for list with size {base.Settings.Count}. Falling back to Settings.Add"); base.Settings.Add((ModSetting)(object)val); } else { base.Settings.Insert(Index, (ModSetting)(object)val); } return val; } public ModSettingFolder AddFolder(string name, string description = "") { //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (base.Settings.Count > 0 && base.Settings.Exists((ModSetting x) => x.Name == name)) { MelonLogger.Warning("AddToList failed: Name not unique: " + name); return null; } ModSettingFolder obj = new ModSettingFolder { Name = name, Description = description }; ((ModSetting)obj).Value = ""; ((ModSetting)obj).SavedValue = ""; ((ModSetting)obj).LinkGroup = 0; ((ModSetting)obj).ValueType = (AvailableTypes)0; ModSettingFolder modSettingFolder = obj; Tags tags = new Tags(); ((Tags)tags).DoNotSave = true; ((Tags)tags).IsEmpty = true; ((Mod)this).AddTags((ModSetting)(object)modSettingFolder, (Tags)(object)tags); base.Settings.Add((ModSetting)(object)modSettingFolder); return modSettingFolder; } } public class RumbleModUIPlusClass : MelonMod { [HarmonyPatch(typeof(UI), "DoOnSettingsSelect")] private static class UI_DoOnSettingsSelect_Patch { private static void Prefix(UI __instance) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Invalid comparison between Unknown and I4 Mod selectedMod = getSelectedMod(__instance); int selectedModSettingIndex = getSelectedModSettingIndex(__instance); if (!(selectedMod.Settings[selectedModSettingIndex] is ModSettingFolder modSettingFolder)) { return; } UI_OnSettingsSelectionChange_Patch.Empty(__instance); List<string> val = new List<string>(); val.Add("<―― back"); List<LinkGroup> linkGroups = selectedMod.LinkGroups; Dictionary<int, int> dictionary = UI_OnSettingsSelectionChange_Patch.ItemLookup[__instance]; dictionary.Add(0, selectedMod.Settings.IndexOf((ModSetting)(object)modSettingFolder.Parent)); int num = -1; int i = 0; int count = val.Count; for (; i < selectedMod.Settings.Count; i++) { ModSetting setting = selectedMod.Settings[i]; if (i == selectedModSettingIndex) { num = count; dictionary.Add(count++, i); val.Add(setting.Name); } else { if (!modSettingFolder.Settings.Contains(setting)) { continue; } dictionary.Add(count++, i); if ((int)setting.ValueType == 5 && setting.LinkGroup != 0) { val.Add(linkGroups.Find((LinkGroup x) => x.Index == setting.LinkGroup).Name + " - " + setting.Name); } else { val.Add(setting.Name); } } } UI_OnSettingsSelectionChange_Patch.SimplifyItemLookup(__instance, dictionary); TMP_Dropdown uI_DropDown_Settings = getUI_DropDown_Settings(__instance); uI_DropDown_Settings.ClearOptions(); uI_DropDown_Settings.AddOptions(val); if (num == -1) { MelonLogger.Error("Could not find selected ModSettingFolder"); } else { uI_DropDown_Settings.SetValueWithoutNotify(num); } } } [HarmonyPatch(typeof(UI), "DoOnModSelect")] private static class UI_DoOnModSelect_Patch { private class SettingOverride { internal int firstSummary = -1; internal int firstNonFolder = -1; } private static readonly Dictionary<UI, SettingOverride> settingOverride = new Dictionary<UI, SettingOverride>(); private static readonly Dictionary<UI, int> settingIdx = new Dictionary<UI, int>(); private static void Prefix(UI __instance) { if ((int)SettingsOverride.GetValue(__instance) == 0) { settingOverride.Add(__instance, new SettingOverride()); } settingIdx.Add(__instance, 0); UI_OnSettingsSelectionChange_Patch.Empty(__instance); } private static bool DoContinue(UI instance, ModSetting setting) { int value = settingIdx[instance]++; if (setting.Tags is Tags tags && tags.InFolder) { return true; } int count = UI_OnSettingsSelectionChange_Patch.ItemLookup[instance].Count; if (settingOverride.TryGetValue(instance, out var value2)) { if (value2.firstSummary == -1 && setting.Tags.IsSummary) { value2.firstSummary = count; } else if (value2.firstNonFolder == -1 && !(setting is ModSettingFolder)) { value2.firstNonFolder = count; } } UI_OnSettingsSelectionChange_Patch.ItemLookup[instance].Add(count, value); return false; } private static void Finalizer(UI __instance) { if (__instance != null) { settingOverride.Remove(__instance); if (!settingIdx.Remove(__instance)) { MelonLogger.Error("Removal of UI from settingIdx failed"); } if (UI_OnSettingsSelectionChange_Patch.ItemLookup.TryGetValue(__instance, out var value)) { UI_OnSettingsSelectionChange_Patch.SimplifyItemLookup(__instance, value); } } } private static void SettingsOverrideHelper(UI instance) { if (settingOverride.TryGetValue(instance, out var value)) { SettingsOverride.SetValue(instance, (value.firstSummary != -1) ? value.firstSummary : ((value.firstNonFolder != -1) ? value.firstNonFolder : 0)); settingOverride.Remove(instance); } } private static int LookupSetting(UI instance, int settingOverride) { if (!UI_OnSettingsSelectionChange_Patch.ItemLookup.TryGetValue(instance, out var value) || !value.TryGetValue(settingOverride, out var value2)) { return settingOverride; } return value2; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Expected O, but got Unknown //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Expected O, but got Unknown //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Expected O, but got Unknown //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Expected O, but got Unknown //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Expected O, but got Unknown //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected O, but got Unknown //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Expected O, but got Unknown //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Expected O, but got Unknown //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Expected O, but got Unknown //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Expected O, but got Unknown //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Expected O, but got Unknown //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Expected O, but got Unknown //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Expected O, but got Unknown Label label = default(Label); return new CodeMatcher(instructions, generator).Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[3] { new CodeMatch((OpCode?)OpCodes.Ldloca_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Brtrue, (object)null, (string)null) }).ThrowIfInvalid("Could not match end of foreach in DoOnModSelect") .CreateLabel(ref label) .Start() .MatchForward(true, (CodeMatch[])(object)new CodeMatch[6] { new CodeMatch((OpCode?)OpCodes.Ldloc_2, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloca_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Call, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Nop, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_2, (object)null, (string)null) }) .ThrowIfInvalid("Could not match start of foreach in DoOnModSelect") .Insert((CodeInstruction[])(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldloc_2, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(UI).GetNestedType("<>c__DisplayClass92_0", BindingFlags.Instance | BindingFlags.NonPublic), "setting")), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(UI_DoOnModSelect_Patch), "DoContinue", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Brtrue, (object)label) }) .MatchForward(false, (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Cgt_Un, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stloc_S, (object)null, (string)null) }) .ThrowIfInvalid("Could not match: this.SettingsOverride != 0") .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(UI_DoOnModSelect_Patch), "SettingsOverrideHelper", (Type[])null, (Type[])null)) }) .RemoveInstructions(8) .MatchForward(false, (CodeMatch[])(object)new CodeMatch[4] { new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)null, (string)null) }) .ThrowIfInvalid("Could not match: this.SettingsSelection = this.SettingsOverride") .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Ldarg_0, (object)null) }) .Advance(4) .Insert((CodeInstruction[])(object)new CodeInstruction[1] { new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(UI_DoOnModSelect_Patch), "LookupSetting", (Type[])null, (Type[])null)) }) .MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.PropertySetter(typeof(TMP_Dropdown), "value"), (string)null) }) .ThrowIfInvalid("Could not match callvirt TMP_Dropdown.value setter") .SetOperandAndAdvance((object)AccessTools.Method(typeof(TMP_Dropdown), "SetValueWithoutNotify", new Type[1] { typeof(int) }, (Type[])null)) .MatchForward(false, (CodeMatch[])(object)new CodeMatch[5] { new CodeMatch((OpCode?)OpCodes.Nop, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldc_I4_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Stfld, (object)AccessTools.Field(typeof(UI), "SettingsSelection"), (string)null), new CodeMatch((OpCode?)OpCodes.Nop, (object)null, (string)null) }) .ThrowIfInvalid("Could not match else") .Advance(-1) .RemoveInstructions(6) .InstructionEnumeration(); } } [HarmonyPatch(typeof(UI), "OnSettingsSelectionChange")] private static class UI_OnSettingsSelectionChange_Patch { internal static readonly Dictionary<UI, Dictionary<int, int>> ItemLookup = new Dictionary<UI, Dictionary<int, int>>(); internal static void SimplifyItemLookup(UI instance, Dictionary<int, int> map) { foreach (int item in map.Keys.Where((int k) => (k != 0) ? (map[k] == k) : (map[0] == 0)).ToList()) { map.Remove(item); } if (map.Count == 0) { ItemLookup.Remove(instance); } } private static bool Prefix(UI __instance, ref int Input) { if (ItemLookup.TryGetValue(__instance, out var value) && value.TryGetValue(Input, out var value2)) { if (value2 == -1) { SettingsOverride.SetValue(__instance, 0); DoOnModSelect.Invoke(__instance, null); return false; } Input = value2; } return true; } internal static void Empty(UI instance) { if (!ItemLookup.TryAdd(instance, new Dictionary<int, int>())) { ItemLookup[instance].Clear(); } } } private static class Mod_Log_Patches { private static readonly CodeMatch MelonLoggerMsg = new CodeMatch((OpCode?)OpCodes.Call, (object)AccessTools.Method(typeof(MelonLogger), "Msg", new Type[1] { typeof(string) }, (Type[])null), (string)null); private static readonly CodeInstruction MelonLoggerWarning = new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(MelonLogger), "Warning", new Type[1] { typeof(string) }, (Type[])null)); private static HarmonyMethod GetTranspiler => new HarmonyMethod(typeof(Mod_Log_Patches).GetMethod("Transpiler", BindingFlags.Static | BindingFlags.NonPublic)); internal static void PatchAll(Harmony harmony) { MethodInfo[] methods = typeof(Mod).GetMethods(); foreach (MethodInfo methodInfo in methods) { if (methodInfo.DeclaringType == typeof(Mod)) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, GetTranspiler, (HarmonyMethod)null, (HarmonyMethod)null); } } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return new CodeMatcher(instructions, generator).Start().MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { MelonLoggerMsg }).Repeat((Action<CodeMatcher>)delegate(CodeMatcher match) { match.RemoveInstruction(); match.InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[1] { MelonLoggerWarning }); }, (Action<string>)null) .InstructionEnumeration(); } } [HarmonyPatch(typeof(UI), "SaveSettings")] private static class UI_SaveSettings_Patch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { yield return instruction; if (instruction.opcode == OpCodes.Ldstr && instruction.operand is string text && text.StartsWith("Created by: ")) { yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null); yield return Transpilers.EmitDelegate<Func<string, UI, string>>((Func<string, UI, string>)((string str, UI instance) => (!(getSelectedMod(instance) is Mod)) ? str : (str + " and RumbleModUIPlus 2.0.0"))); } } } } [HarmonyPatch(typeof(Mod), "GetFromFile")] private static class Mod_GetFromFile_Patch { private static bool Prefix(Mod __instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Folders val = (Folders)Mod_Folders.GetValue(__instance); bool flag = (bool)Mod_debug.GetValue(__instance); string subFolder = val.GetSubFolder(0); string path = ((subFolder == null) ? val.GetFolderString("", false) : val.GetFolderString(subFolder, false)) + "\\" + __instance.SettingsFile; if (File.Exists(path)) { string[] array = File.ReadAllLines(path); if (array.Length >= 2 && array[0] == __instance.ModName + " " + ((__instance is Mod mod) ? mod.ModFormatVersion : __instance.ModVersion)) { HashSet<ModSetting> hashSet = new HashSet<ModSetting>(); for (int i = 2; i < array.Length; i++) { string text = array[i]; foreach (ModSetting setting in __instance.Settings) { if (!hashSet.Contains(setting) && !setting.Tags.DoNotSave && text.StartsWith(setting.Name + ": ")) { MethodInfo mod_ValueValidation = Mod_ValueValidation; object[] array2 = new object[2]; string text2 = text; int num = setting.Name.Length + 2; array2[0] = text2.Substring(num, text2.Length - num); array2[1] = setting; if ((bool)mod_ValueValidation.Invoke(__instance, array2)) { setting.SavedValue = setting.Value; } else { MelonLogger.Msg(__instance.ModName + " - " + setting.Name + " File Read Error."); } if (flag) { MelonLogger.Msg(__instance.ModName + " - " + setting.Name + " " + setting.Value); } hashSet.Add(setting); break; } } } Mod_IsFileLoadedSetter.Invoke(__instance, new object[1] { true }); } else { Mod_IsFileLoadedSetter.Invoke(__instance, new object[1] { false }); if (array.Length < 2) { MelonLogger.Error("Could not load " + __instance.ModName + "'s settings because there were less than two lines in the settings file."); } else if (flag) { MelonLogger.Warning(__instance.ModName + "'s settings did not match pattern."); } } } return false; } } [HarmonyPatch(typeof(Mod), "SaveModData")] private static class Mod_SaveModData { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo get_ModVersion = AccessTools.PropertyGetter(typeof(Mod), "ModVersion"); foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Call && instruction.operand is MethodInfo methodInfo && methodInfo == get_ModVersion) { yield return Transpilers.EmitDelegate<Func<Mod, string>>((Func<Mod, string>)((Mod instance) => (!(instance is Mod mod)) ? instance.ModVersion : mod.ModFormatVersion)); } else { yield return instruction; } } } } private static FieldInfo Mod_Options = AccessTools.Field(typeof(UI), "Mod_Options"); private static FieldInfo ModSelection = AccessTools.Field(typeof(UI), "ModSelection"); private static FieldInfo SettingsSelection = AccessTools.Field(typeof(UI), "SettingsSelection"); private static FieldInfo SettingsOverride = AccessTools.Field(typeof(UI), "SettingsOverride"); private static FieldInfo UI_DropDown_Settings = AccessTools.Field(typeof(UI), "UI_DropDown_Settings"); private static MethodInfo DoOnModSelect = AccessTools.Method(typeof(UI), "DoOnModSelect", (Type[])null, (Type[])null); private static FieldInfo Mod_Folders = AccessTools.Field(typeof(Mod), "Folders"); private static FieldInfo Mod_debug = AccessTools.Field(typeof(Mod), "debug"); private static MethodInfo Mod_IsFileLoadedSetter = AccessTools.PropertySetter(typeof(Mod), "IsFileLoaded"); private static MethodInfo Mod_ValueValidation = AccessTools.Method(typeof(Mod), "ValueValidation", (Type[])null, (Type[])null); public override void OnInitializeMelon() { Mod_Log_Patches.PatchAll(((MelonBase)this).HarmonyInstance); } private static Mod getSelectedMod(UI instance) { return ((List<Mod>)Mod_Options.GetValue(instance))[(int)ModSelection.GetValue(instance)]; } private static int getSelectedModSettingIndex(UI instance) { return (int)SettingsSelection.GetValue(instance); } private static TMP_Dropdown getUI_DropDown_Settings(UI instance) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) return ((GameObject)UI_DropDown_Settings.GetValue(instance)).GetComponent<TMP_Dropdown>(); } public static Mod GetSelectedMod() { return getSelectedMod(UI.instance); } public static ModSetting GetSelectedModSetting() { return getSelectedMod(UI.instance).Settings[getSelectedModSettingIndex(UI.instance)]; } } public class ModSettingFolder : ModSetting { public readonly HashSet<ModSetting> Settings = new HashSet<ModSetting>(); internal ModSettingFolder Parent; public override object Value { get; set; } public override object SavedValue { get; set; } public ModSettingFolder AddSetting(ModSetting setting) { if (setting.Tags is Tags tags) { tags.InFolder = true; } else { setting.Tags = (Tags)(object)new Tags(setting.Tags) { InFolder = true }; } if (setting is ModSettingFolder modSettingFolder) { modSettingFolder.Parent = this; } Settings.Add(setting); return this; } public bool RemoveSetting(ModSetting setting) { ((Tags)(object)setting.Tags).InFolder = false; if (setting is ModSettingFolder modSettingFolder) { modSettingFolder.Parent = null; } return Settings.Remove(setting); } public ModSettingFolder RemoveSettingC(ModSetting setting, out bool success) { success = RemoveSetting(setting); return this; } public ModSettingFolder RemoveSettingC(ModSetting setting) { RemoveSetting(setting); return this; } public ModSettingFolder RemoveAllSettings() { foreach (ModSetting setting in Settings) { RemoveSetting(setting); } return this; } public bool RemoveFolder(List<ModSetting> settings) { RemoveAllSettings(); return settings.Remove((ModSetting)(object)this); } public bool RemoveFolder(Mod mod) { return RemoveFolder(mod.Settings); } public override string GetValueAsString() { return ""; } } public class Tags : Tags { public bool InFolder { get; set; } public Tags() { InFolder = false; } public Tags(Tags tags) : this() { ((Tags)this).IsSummary = tags.IsSummary; ((Tags)this).IsEmpty = tags.IsEmpty; ((Tags)this).IsCustom = tags.IsCustom; ((Tags)this).CustomString = tags.CustomString; ((Tags)this).IsPassword = tags.IsPassword; ((Tags)this).DoNotSave = tags.DoNotSave; } }