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 SketchbookPlus v1.3.1
Mods/SketchbookPlus.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppRUMBLE.Managers; using Il2CppRUMBLE.Players; using Il2CppRUMBLE.Utilities; using MelonLoader; using MelonLoader.Preferences; using RumbleModdingAPI.RMAPI; using SketchbookPlus; using UIFramework; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(main), "SketchbookPlus", "1.3.1", "UlvakSkillz", null)] [assembly: MelonGame("Buckethead Entertainment", "RUMBLE")] [assembly: MelonColor(255, 195, 0, 255)] [assembly: MelonAuthorColor(255, 195, 0, 255)] [assembly: VerifyLoaderVersion(0, 6, 6, true)] [assembly: MelonAdditionalDependencies(new string[] { "UIFramework" })] [assembly: AssemblyDescription("")] [assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("3b03f008-9dbb-4382-a110-b59ee8b632ca")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("SketchbookPlus")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f862b9cde5a452b3962bff9868f09b89b6c13811")] [assembly: AssemblyProduct("SketchbookPlus")] [assembly: AssemblyTitle("SketchbookPlus")] [assembly: AssemblyVersion("1.0.0.0")] namespace SketchbookPlus; public static class BuildInfo { public const string ModName = "SketchbookPlus"; public const string ModVersion = "1.3.1"; public const string Author = "UlvakSkillz"; } public class main : MelonMod { [CompilerGenerated] private sealed class <checkPlayer>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Player player; public main <>4__this; private string <visuals>5__1; private string <name>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <checkPlayer>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <visuals>5__1 = null; <name>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this.debugLog("Storing Player"); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; <visuals>5__1 = <>4__this.getOutfitString(player.Data.VisualData); <name>5__2 = player.Data.GeneralData.PublicUsername; if (<name>5__2.Contains("<") || <name>5__2.Contains(">") || <name>5__2.Contains(":")) { <name>5__2 = <name>5__2.Replace("<", "_"); <name>5__2 = <name>5__2.Replace(">", "_"); <name>5__2 = <name>5__2.Replace(":", "_"); } if (!File.Exists("UserData\\SketchbookPlus\\Stored\\" + <name>5__2 + ".txt")) { <>4__this.debugLog("Saving " + <name>5__2 + "'s Model"); } else { <>4__this.debugLog("Found Existing " + <name>5__2 + "'s Model, Overriding Text"); } <>4__this.saveFile(<visuals>5__1, "UserData\\SketchbookPlus\\Stored\\" + <name>5__2 + ".txt"); 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 Random random = new Random(DateTime.Now.Millisecond * DateTime.Now.Second * DateTime.Now.Minute); private List<string> acceptedFiles = new List<string>(); private List<string> failedFiles = new List<string>(); private List<string> pendingFiles = new List<string>(); private List<string> acceptedFilesTexts = new List<string>(); private List<string> pendingFilesTexts = new List<string>(); private List<List<int>> acceptedItems = new List<List<int>>(); private bool randomizerInit = false; private int lastOutfit = -1; private void Log(string msg) { MelonLogger.Msg(msg); } private void debugLog(string msg) { if (Preferences.PrefDebugging.Value) { MelonLogger.Msg("-" + msg); } } public override void OnLateInitializeMelon() { if (!Directory.Exists("UserData\\SketchbookPlus")) { Directory.CreateDirectory("UserData\\SketchbookPlus"); } if (!Directory.Exists("UserData\\SketchbookPlus\\Stored")) { Directory.CreateDirectory("UserData\\SketchbookPlus\\Stored"); } if (!File.Exists("UserData\\SketchbookPlus\\BlackListedItems.txt")) { saveFile("", "UserData\\SketchbookPlus\\BlackListedItems.txt", addAcceptedFile: false); } Actions.onMapInitialized += mapInit; Actions.onPlayerSpawned += playerJoined; pendingFiles.Clear(); acceptedFiles.Clear(); failedFiles.Clear(); } public override void OnInitializeMelon() { Preferences.InitPrefs(); ((ModelModItem)UI.Register((MelonBase)(object)this, (MelonPreferences_Category[])(object)new MelonPreferences_Category[3] { Preferences.SketchbookPlusCategory, Preferences.SaveLoadCategory, Preferences.RandomizerCategory })).OnModSaved += Save; } private void Save() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown debugLog("Main Method Running"); PlayerVisualData visualData = Singleton<PlayerManager>.instance.localPlayer.Data.VisualData; PlayerVisualData val = new PlayerVisualData(visualData); int[] array = new int[acceptedItems.Count]; if (Preferences.PrefUpdateFilesTexts.Value) { debugLog("Clearing Known Files"); ((MelonPreferences_Entry)Preferences.PrefUpdateFilesTexts).ResetToDefault(); pendingFiles.Clear(); acceptedFiles.Clear(); failedFiles.Clear(); } debugLog("Rechecking Files"); recheckFiles(); debugLog("Done Rechecking Files"); if (!Preferences.PrefSavedOutfitName.Value.ToLower().EndsWith(".txt")) { MelonPreferences_Entry<string> prefSavedOutfitName = Preferences.PrefSavedOutfitName; prefSavedOutfitName.Value += ".txt"; } if (!Preferences.PrefOutfitNameToLoad.Value.ToLower().EndsWith(".txt")) { MelonPreferences_Entry<string> prefOutfitNameToLoad = Preferences.PrefOutfitNameToLoad; prefOutfitNameToLoad.Value += ".txt"; } if (Preferences.PrefOutfitTypeToLoad.Value == OutfitTypes.RandomizerOutfit) { debugLog("Starting Randomizer"); string[] array2 = getOutfitString(visualData).Split(","); debugLog("Got Original Outfit"); int[] array3 = new int[20] { 0, 1, 2, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 58, 59, 60, 61, 62, 63, 64 }; int[] array4 = new int[6] { 3, 4, 5, 6, 7, 8 }; int[] array5 = new int[30] { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 }; int[] array6 = new int[9] { 19, 20, 21, 22, 23, 24, 25, 26, 27 }; string[] array7 = new string[array3.Length + array4.Length + array5.Length + array6.Length]; debugLog("Set PVD Variable Spots"); for (int i = 0; i < array2.Length; i++) { array7[i] = array2[i]; } debugLog("Updated New PVD Variables"); for (int j = 0; j < array3.Length + array4.Length + array5.Length + array6.Length; j++) { if ((Preferences.PrefRandomizerIdentity.Value && array3.Contains(j)) || (Preferences.PrefRandomizerArmorColors.Value && array4.Contains(j)) || (Preferences.PrefArmorItems.Value && array6.Contains(j)) || (Preferences.PrefRandomizerMarkings.Value && array5.Contains(j))) { array7[j] = acceptedItems[j][random.Next(0, acceptedItems[j].Count)].ToString(); } } debugLog("Outfit Ready to Set"); setPVD(visualData, array7); Log("Randomizer Outfit Set: " + getOutfitString(visualData)); } else if (Preferences.PrefSaveOutfit.Value) { ((MelonPreferences_Entry)Preferences.PrefSaveOutfit).ResetToDefault(); debugLog("Saving Outfit: UserData\\SketchbookPlus\\" + Preferences.PrefSavedOutfitName.Value); string outfitString = getOutfitString(Singleton<PlayerManager>.instance.localPlayer.Data.VisualData); debugLog("File Text: " + outfitString); saveFile(outfitString, "UserData\\SketchbookPlus\\" + Preferences.PrefSavedOutfitName.Value); } else { if (!(Scene.GetSceneName() == "Gym")) { return; } if (Preferences.PrefOutfitTypeToLoad.Value == OutfitTypes.RandomFromFilesOutfit && acceptedFiles.Count > 0) { int num = random.Next(0, acceptedFiles.Count); while (num == lastOutfit && acceptedFiles.Count > 1) { num = random.Next(0, acceptedFiles.Count); } debugLog("Loading Random: " + acceptedFiles[num]); loadOutfit(acceptedFiles[num]); lastOutfit = num; } else if (Preferences.PrefOutfitTypeToLoad.Value == OutfitTypes.SavedOutfit) { debugLog("Loading Selected: " + Preferences.PrefOutfitNameToLoad.Value); loadOutfit("UserData\\SketchbookPlus\\" + Preferences.PrefOutfitNameToLoad.Value); } } } private void recheckFiles() { string[] files = Directory.GetFiles("UserData\\SketchbookPlus"); string[] array = files; foreach (string text in array) { if (!(text == "UserData\\SketchbookPlus\\config.cfg") && !(text == "UserData\\SketchbookPlus\\BlackListedItems.txt") && !failedFiles.Contains(text) && !acceptedFiles.Contains(text)) { debugLog("Pending File: " + text); pendingFiles.Add(text); } } loadFileTexts(); while (pendingFiles.Count > 0) { if (!CheckFileValidity(pendingFiles[0])) { Log("Removing Bad File: " + pendingFiles[0]); Log("Removing Bad File's Text: " + pendingFilesTexts[0]); failedFiles.Add(pendingFiles[0]); pendingFiles.Remove(pendingFiles[0]); pendingFilesTexts.RemoveAt(0); } else { debugLog("Accepting file: " + pendingFiles[0]); acceptedFiles.Add(pendingFiles[0]); acceptedFilesTexts.Add(pendingFilesTexts[0]); pendingFiles.Remove(pendingFiles[0]); pendingFilesTexts.RemoveAt(0); } } } private void saveFile(string textToSave, string file, bool addAcceptedFile = true) { if (!File.Exists(file)) { acceptedFiles.Add(file); } FileStream fileStream = File.Create(file); byte[] bytes = Encoding.UTF8.GetBytes(textToSave); fileStream.Write(bytes); fileStream.Close(); fileStream.Dispose(); Log("Saving " + file + " Complete"); } private void playerJoined(Player player) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 if (Preferences.PrefStoreOthersOutfits.Value && (int)player.Controller.controllerType == 2) { MelonCoroutines.Start(checkPlayer(player)); } } [IteratorStateMachine(typeof(<checkPlayer>d__17))] private IEnumerator checkPlayer(Player player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <checkPlayer>d__17(0) { <>4__this = this, player = player }; } private void setupRandomizer() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown debugLog("Setting Up Randomizer"); int num = 50; PlayerVisualData visualData = Singleton<PlayerManager>.instance.localPlayer.Data.VisualData; PlayerVisualData val = new PlayerVisualData(visualData); setPVD(val, visualData); string outfitString = getOutfitString(visualData); string[] array = outfitString.Split(","); int[] array2 = new int[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = int.Parse(array[i]); } for (int j = 0; j < array.Length; j++) { List<int> list = new List<int>(); string text = "Spot " + j + ": "; for (int k = 0; k <= num; k++) { array2[j] = k; string[] array3 = new string[array2.Length]; for (int l = 0; l < array3.Length; l++) { array3[l] = array2[l].ToString(); } setPVD(val, array3); if (checkItems(val.ToPlayfabDataString(), isSilent: true)) { list.Add(k); text = text + k + ", "; } } acceptedItems.Add(list); debugLog(text); for (int m = 0; m < array.Length; m++) { array2[m] = int.Parse(array[m]); } } setupBlackList(); debugLog("Randomizer Setup"); randomizerInit = true; } private void setupBlackList() { string[] array = File.ReadAllLines("UserData\\SketchbookPlus\\BlackListedItems.txt"); try { string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(","); if (acceptedItems[int.Parse(array3[0])].Remove(int.Parse(array3[1]))) { Log("Removed Item: " + text); } } } catch { MelonLogger.Error("Error Reading BlackList File"); } } private string getOutfitString(PlayerVisualData pvd) { string text = ""; for (int i = 0; i < ((Il2CppArrayBase<short>)(object)pvd.ColorationIndexes).Count; i++) { text = text + ((Il2CppArrayBase<short>)(object)pvd.ColorationIndexes)[i] + ","; } for (int j = 0; j < ((Il2CppArrayBase<short>)(object)pvd.CustomizationPartIndexes).Count; j++) { text = text + ((Il2CppArrayBase<short>)(object)pvd.CustomizationPartIndexes)[j] + ","; } for (int k = 0; k < ((Il2CppArrayBase<short>)(object)pvd.OtherCustomizationIndexes).Count; k++) { text = text + ((Il2CppArrayBase<short>)(object)pvd.OtherCustomizationIndexes)[k] + ","; } for (int l = 0; l < ((Il2CppArrayBase<short>)(object)pvd.TextureCustomizationIndexes).Count; l++) { text = text + ((Il2CppArrayBase<short>)(object)pvd.TextureCustomizationIndexes)[l] + ","; } for (int m = 0; m < ((Il2CppArrayBase<short>)(object)pvd.TextureOpacityIndexes).Count; m++) { text = text + ((Il2CppArrayBase<short>)(object)pvd.TextureOpacityIndexes)[m] + ","; } for (int n = 0; n < ((Il2CppArrayBase<short>)(object)pvd.WeightAdjustementIndexes).Count; n++) { text += ((Il2CppArrayBase<short>)(object)pvd.WeightAdjustementIndexes)[n]; if (n != ((Il2CppArrayBase<short>)(object)pvd.WeightAdjustementIndexes).Count - 1) { text += ","; } } return text; } private void loadOutfit(string fileName) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown if (acceptedFiles.IndexOf(fileName) == -1) { MelonLogger.Error("Not An Accepted File: " + fileName); return; } Log("Text: " + acceptedFilesTexts[acceptedFiles.IndexOf(fileName)]); string[] data = acceptedFilesTexts[acceptedFiles.IndexOf(fileName)].Split(','); PlayerVisualData visualData = Singleton<PlayerManager>.instance.localPlayer.Data.VisualData; PlayerVisualData val = new PlayerVisualData(visualData); setPVD(val, data); if (checkItems(val.ToPlayfabDataString())) { debugLog("Setting PVD Now"); setPVD(visualData, val); Log("Loaded Outfit for Next Scene: " + fileName); } } private bool CheckFileValidity(string fileName) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown string[] data = pendingFilesTexts[pendingFiles.IndexOf(fileName)].Split(','); PlayerVisualData val = new PlayerVisualData(Singleton<PlayerManager>.instance.localPlayer.Data.VisualData); try { setPVD(val, data); } catch { Log("Invalid File Text"); return false; } return checkItems(val.ToPlayfabDataString()); } private void setPVD(PlayerVisualData pvd, string[] data) { int num = 0; for (int i = 0; i < ((Il2CppArrayBase<short>)(object)pvd.ColorationIndexes).Count; i++) { ((Il2CppArrayBase<short>)(object)pvd.ColorationIndexes)[i] = short.Parse(data[num]); num++; } for (int j = 0; j < ((Il2CppArrayBase<short>)(object)pvd.CustomizationPartIndexes).Count; j++) { ((Il2CppArrayBase<short>)(object)pvd.CustomizationPartIndexes)[j] = short.Parse(data[num]); num++; } for (int k = 0; k < ((Il2CppArrayBase<short>)(object)pvd.OtherCustomizationIndexes).Count; k++) { ((Il2CppArrayBase<short>)(object)pvd.OtherCustomizationIndexes)[k] = short.Parse(data[num]); num++; } for (int l = 0; l < ((Il2CppArrayBase<short>)(object)pvd.TextureCustomizationIndexes).Count; l++) { ((Il2CppArrayBase<short>)(object)pvd.TextureCustomizationIndexes)[l] = short.Parse(data[num]); num++; } for (int m = 0; m < ((Il2CppArrayBase<short>)(object)pvd.TextureOpacityIndexes).Count; m++) { ((Il2CppArrayBase<short>)(object)pvd.TextureOpacityIndexes)[m] = short.Parse(data[num]); num++; } for (int n = 0; n < ((Il2CppArrayBase<short>)(object)pvd.WeightAdjustementIndexes).Count; n++) { ((Il2CppArrayBase<short>)(object)pvd.WeightAdjustementIndexes)[n] = short.Parse(data[num]); num++; } } private void setPVD(PlayerVisualData pvdTo, PlayerVisualData pvdFrom) { for (int i = 0; i < ((Il2CppArrayBase<short>)(object)pvdTo.ColorationIndexes).Count; i++) { ((Il2CppArrayBase<short>)(object)pvdTo.ColorationIndexes)[i] = ((Il2CppArrayBase<short>)(object)pvdFrom.ColorationIndexes)[i]; } for (int j = 0; j < ((Il2CppArrayBase<short>)(object)pvdTo.CustomizationPartIndexes).Count; j++) { ((Il2CppArrayBase<short>)(object)pvdTo.CustomizationPartIndexes)[j] = ((Il2CppArrayBase<short>)(object)pvdFrom.CustomizationPartIndexes)[j]; } for (int k = 0; k < ((Il2CppArrayBase<short>)(object)pvdTo.OtherCustomizationIndexes).Count; k++) { ((Il2CppArrayBase<short>)(object)pvdTo.OtherCustomizationIndexes)[k] = ((Il2CppArrayBase<short>)(object)pvdFrom.OtherCustomizationIndexes)[k]; } for (int l = 0; l < ((Il2CppArrayBase<short>)(object)pvdTo.TextureCustomizationIndexes).Count; l++) { ((Il2CppArrayBase<short>)(object)pvdTo.TextureCustomizationIndexes)[l] = ((Il2CppArrayBase<short>)(object)pvdFrom.TextureCustomizationIndexes)[l]; } for (int m = 0; m < ((Il2CppArrayBase<short>)(object)pvdTo.TextureOpacityIndexes).Count; m++) { ((Il2CppArrayBase<short>)(object)pvdTo.TextureOpacityIndexes)[m] = ((Il2CppArrayBase<short>)(object)pvdFrom.TextureOpacityIndexes)[m]; } for (int n = 0; n < ((Il2CppArrayBase<short>)(object)pvdTo.WeightAdjustementIndexes).Count; n++) { ((Il2CppArrayBase<short>)(object)pvdTo.WeightAdjustementIndexes)[n] = ((Il2CppArrayBase<short>)(object)pvdFrom.WeightAdjustementIndexes)[n]; } } private bool checkItems(string tempPVDEconomyDataString, bool isSilent = false) { string[] array = tempPVDEconomyDataString.Split(':'); bool flag = true; for (int i = 0; i < array.Length; i++) { if (i == 0 || i == 5) { continue; } string[] array2 = array[i].Split(","); string[] array3 = array2; foreach (string text in array3) { if (!Singleton<PlayerManager>.instance.localPlayer.Data.EconomyData.ReceivedItems.Contains(text)) { flag = false; if (!isSilent) { Log("Item Not Redeemed"); } break; } } if (!flag) { break; } } if (flag) { return true; } return false; } private void mapInit(string map) { debugLog("RMAPI triggered MapInit"); if (map == "Gym") { debugLog("Map is Gym"); if (!randomizerInit) { debugLog("Setting up Randomizer"); setupRandomizer(); } Save(); } } private void loadFileTexts() { foreach (string pendingFile in pendingFiles) { string item = File.ReadAllText(pendingFile); pendingFilesTexts.Add(item); } } } public enum OutfitTypes { [Display(Name = "None")] None, [Display(Name = "Outfit From Selected File")] SavedOutfit, [Display(Name = "Random Outfit From Files")] RandomFromFilesOutfit, [Display(Name = "Randomizer Outfit")] RandomizerOutfit } public class Preferences { private const string CONFIG_FILE = "config.cfg"; private const string USER_DATA = "UserData/SketchbookPlus/"; internal static Dictionary<MelonPreferences_Entry, object> LastSavedValues = new Dictionary<MelonPreferences_Entry, object>(); internal static MelonPreferences_Category SketchbookPlusCategory; internal static MelonPreferences_Entry<OutfitTypes> PrefOutfitTypeToLoad; internal static MelonPreferences_Entry<bool> PrefStoreOthersOutfits; internal static MelonPreferences_Entry<bool> PrefUpdateFilesTexts; internal static MelonPreferences_Entry<bool> PrefDebugging; internal static MelonPreferences_Category SaveLoadCategory; internal static MelonPreferences_Entry<bool> PrefSaveOutfit; internal static MelonPreferences_Entry<string> PrefSavedOutfitName; internal static MelonPreferences_Entry<string> PrefOutfitNameToLoad; internal static MelonPreferences_Category RandomizerCategory; internal static MelonPreferences_Entry<bool> PrefRandomizerIdentity; internal static MelonPreferences_Entry<bool> PrefRandomizerArmorColors; internal static MelonPreferences_Entry<bool> PrefArmorItems; internal static MelonPreferences_Entry<bool> PrefRandomizerMarkings; internal static void InitPrefs() { if (!Directory.Exists("UserData/SketchbookPlus/")) { Directory.CreateDirectory("UserData/SketchbookPlus/"); } SketchbookPlusCategory = MelonPreferences.CreateCategory("SketchbookPlus", "Settings"); SketchbookPlusCategory.SetFilePath(Path.Combine("UserData/SketchbookPlus/", "config.cfg")); PrefOutfitTypeToLoad = SketchbookPlusCategory.CreateEntry<OutfitTypes>("OutfitTypeToLoad", OutfitTypes.None, "Outfit Type to Load", "Selects what type of Outfit to Load", false, false, (ValueValidator)null, (string)null); PrefStoreOthersOutfits = SketchbookPlusCategory.CreateEntry<bool>("StoreOthersOutfits", false, "Store Others Outfits", "Set to True to Store Other Player's Cosmetics to UserData/SketchBookPlus/Stored", false, false, (ValueValidator)null, (string)null); PrefUpdateFilesTexts = SketchbookPlusCategory.CreateEntry<bool>("UpdateFilesTexts", false, "Reload Text Files", "Set to True to refresh the Mod's Data from Files", false, false, (ValueValidator)null, (string)null); PrefDebugging = SketchbookPlusCategory.CreateEntry<bool>("Debugging", false, "Enable Debugging Logs", "Set to True to Show Logs", false, false, (ValueValidator)null, (string)null); SaveLoadCategory = MelonPreferences.CreateCategory("SaveAndLoad", "Save & Load"); SaveLoadCategory.SetFilePath(Path.Combine("UserData/SketchbookPlus/", "config.cfg")); PrefSaveOutfit = SaveLoadCategory.CreateEntry<bool>("SaveOutfit", false, "Save Outfit", "Set to True and Save to Store the Equipped Outfit", false, false, (ValueValidator)null, (string)null); PrefSavedOutfitName = SaveLoadCategory.CreateEntry<string>("SavedOutfitName", "DefaultName", "Saved Outfit Name", "File Name To Save Under", false, false, (ValueValidator)null, (string)null); PrefOutfitNameToLoad = SaveLoadCategory.CreateEntry<string>("OutfitNameToLoad", "DefaultName", "Outfit to Load from File", "File Name To Load", false, false, (ValueValidator)null, (string)null); RandomizerCategory = MelonPreferences.CreateCategory("Randomizer", "Randomizer"); RandomizerCategory.SetFilePath(Path.Combine("UserData/SketchbookPlus/", "config.cfg")); PrefRandomizerIdentity = RandomizerCategory.CreateEntry<bool>("RandomizerIdentity", false, "Identity", "(Sets in Gym) Sets the Player's Identity to a Randomized Selection", false, false, (ValueValidator)null, (string)null); PrefRandomizerArmorColors = RandomizerCategory.CreateEntry<bool>("RandomizerArmorColors", true, "Armor Colors", "(Sets in Gym) Sets the Player's Armor Colors to a Randomized Selection", false, false, (ValueValidator)null, (string)null); PrefArmorItems = RandomizerCategory.CreateEntry<bool>("RandomizerArmorItems", false, "Armor Items", "(Sets in Gym) Sets the Player's Armor Items to a Randomized Selection", false, false, (ValueValidator)null, (string)null); PrefRandomizerMarkings = RandomizerCategory.CreateEntry<bool>("RandomizerMarkings", false, "Markings", "(Sets in Gym) Sets the Player's Markings to a Randomized Selection", false, false, (ValueValidator)null, (string)null); ((MelonPreferences_Entry)PrefSaveOutfit).ResetToDefault(); ((MelonPreferences_Entry)PrefUpdateFilesTexts).ResetToDefault(); StoreLastSavedPrefs(); } internal static void StoreLastSavedPrefs() { List<MelonPreferences_Entry> list = new List<MelonPreferences_Entry>(); list.AddRange(SketchbookPlusCategory.Entries); list.AddRange(SaveLoadCategory.Entries); list.AddRange(RandomizerCategory.Entries); foreach (MelonPreferences_Entry item in list) { LastSavedValues[item] = item.BoxedValue; } } public static bool AnyPrefsChanged() { foreach (KeyValuePair<MelonPreferences_Entry, object> lastSavedValue in LastSavedValues) { if (!lastSavedValue.Key.BoxedValue.Equals(lastSavedValue.Value)) { return true; } } return false; } public static bool IsPrefChanged(MelonPreferences_Entry entry) { if (LastSavedValues.TryGetValue(entry, out var value)) { return !entry.BoxedValue.Equals(value); } return false; } }