using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.DevUtilities; using Il2CppScheduleOne.Persistence; using Il2CppScheduleOne.UI.MainMenu; using Il2CppSystem; using Il2CppSystem.Reflection; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using SaveGameModCheckerNs; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(SaveGameModCheckerClass), "SaveGameModChecker", "1.0.0", "xVilho", null)] [assembly: MelonColor(255, 200, 150, 255)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] namespace SaveGameModCheckerNs; internal static class SaveGameModCheckerConfig { private static MelonPreferences_Category Category; public static MelonPreferences_Entry EnableMod; public static MelonPreferences_Entry WarnOnMissingMods; public static MelonPreferences_Entry WarnOnNewMods; public static MelonPreferences_Entry EnableDebugLogging; public static void Setup() { Category = MelonPreferences.CreateCategory("SaveGameModChecker", "SaveGame Mod Settings"); EnableMod = Category.CreateEntry("EnableMod", true, "Master Switch", "If false, the mod will be completely disabled.", false, false, (ValueValidator)null, (string)null); WarnOnMissingMods = Category.CreateEntry("WarnOnMissingMods", true, "Warn on Missing Mods", "Show mismatch popup if mods from the save are missing.", false, false, (ValueValidator)null, (string)null); WarnOnNewMods = Category.CreateEntry("WarnOnNewMods", true, "Warn on New Mods", "Show mismatch popup if currently installed mods were not in the save.", false, false, (ValueValidator)null, (string)null); EnableDebugLogging = Category.CreateEntry("EnableDebugLogging", false, "Enable Debug Logging", "Whether to output debug logs to the MelonLoader console.", false, false, (ValueValidator)null, (string)null); Category.SaveToFile(true); if (!EnableMod.Value) { SaveGameModCheckerClass.Log("[Config] Master switch is OFF. Mod functionality is suspended."); } else { SaveGameModCheckerClass.Log("[Config] SaveGameModCheckerConfig initialized."); } } } [HarmonyPatch(typeof(LoadManager), "StartGame")] public static class LoadManager_StartGame_Patch { public static SaveInfo StoredSaveInfoToLoad; public static bool BypassNextLoad; public static bool Prefix(LoadManager __instance, SaveInfo info) { //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Expected O, but got Unknown try { if (!SaveGameModCheckerConfig.EnableMod.Value) { return true; } if (info == null) { return true; } if (BypassNextLoad) { BypassNextLoad = false; return true; } int saveSlotNumber = info.SaveSlotNumber; string text = $"SAVEGAME_{saveSlotNumber}"; string normalizedSaveFolderName = SaveGameModCheckerClass.GetNormalizedSaveFolderName(info.SavePath); if (!string.IsNullOrEmpty(normalizedSaveFolderName)) { text = normalizedSaveFolderName; } string text2 = Path.Combine(Path.Combine(MelonEnvironment.UserDataDirectory, "SaveGameModChecker", text), "Mods.txt"); List list = MelonTypeBase.RegisteredMelons.Select((MelonMod m) => ((MelonBase)m).Info.Name).ToList(); bool flag = false; bool flag2 = false; List list2 = new List(); List list3 = new List(); List list4 = new List(); if (File.Exists(text2)) { string[] array = (from s in File.ReadAllLines(text2) select s.Trim() into s where !string.IsNullOrWhiteSpace(s) select s).ToArray(); HashSet hashSet = new HashSet(array); string[] array2 = array; foreach (string item in array2) { if (!list.Contains(item)) { list2.Add(item); flag = true; } else { list4.Add(item); } } foreach (string item2 in list) { if (!hashSet.Contains(item2)) { list3.Add(item2); flag2 = true; } } } if (!flag && !flag2 && File.Exists(text2)) { SaveGameModCheckerClass.Log("Mods match perfectly for " + text + ". Read from " + text2); } bool flag3 = false; if (flag && SaveGameModCheckerConfig.WarnOnMissingMods.Value) { flag3 = true; } if (flag2 && SaveGameModCheckerConfig.WarnOnNewMods.Value) { flag3 = true; } if (flag3) { list2.Sort(); list3.Sort(); list4.Sort(); string text3 = "[WARNING] " + text + " mod mismatch."; if (flag) { text3 = text3 + "\nMissing:\n- " + string.Join("\n- ", list2); } if (flag2) { text3 = text3 + "\nNew (Not in save):\n- " + string.Join("\n- ", list3); } SaveGameModCheckerClass.LogWarning(text3); string text4 = ""; if (flag) { text4 += "MISSING FROM SAVE:\n"; foreach (string item3 in list2) { text4 = text4 + "- " + item3 + "\n"; } } if (flag2) { if (text4 != "") { text4 += "\n"; } text4 += "NEW (NOT IN SAVE):\n"; foreach (string item4 in list3) { text4 = text4 + "- " + item4 + "\n"; } } if (list4.Count > 0) { if (text4 != "") { text4 += "\n"; } text4 += "MATCHED MODS:\n"; foreach (string item5 in list4) { text4 = text4 + "- " + item5 + "\n"; } } Data val = new Data("Mods Mismatch", text4.Trim(), true); StoredSaveInfoToLoad = info; MainMenuPopup val2 = Object.FindObjectOfType(true); if ((Object)(object)val2 != (Object)null) { val2.Open(val); } else { __instance.ExitToMenu((SaveInfo)null, val, false); } return false; } } catch (Exception value) { SaveGameModCheckerClass.LogError($"Error in LoadManager.StartGame prefix: {value}"); } return true; } } [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { })] public static class SaveManager_Save_NoArg_Patch { [HarmonyPostfix] public static void Postfix() { try { SaveGameModCheckerClass.SaveCurrentMods(); } catch (Exception value) { SaveGameModCheckerClass.LogError($"Error in SaveManager.Save() postfix: {value}"); } } } [HarmonyPatch(typeof(SaveManager), "Save", new Type[] { typeof(string) })] public static class SaveManager_Save_String_Patch { [HarmonyPostfix] public static void Postfix(string saveFolderPath) { try { SaveGameModCheckerClass.SaveCurrentMods(saveFolderPath); } catch (Exception value) { SaveGameModCheckerClass.LogError($"Error in SaveManager.Save(string) postfix: {value}"); } } } [HarmonyPatch(typeof(MainMenuPopup), "Open", new Type[] { typeof(Data) })] public static class MainMenuPopup_Open_Patch { private static Button btnSafety; private static Button btnQuit; private static Button btnContinue; private static GameObject scrollContainer; public static void Postfix(MainMenuPopup __instance, Data data) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) try { if (data == null || data.Title != "Mods Mismatch") { return; } Image componentInChildren = ((Component)__instance).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { ((Graphic)componentInChildren).color = new Color(0.01f, 0.01f, 0.01f, 1f); } RectTransform component = ((Component)__instance).GetComponent(); float num = Mathf.Min((float)Screen.width * 0.7f, 950f); float num2 = Mathf.Min((float)Screen.height * 0.8f, 750f); component.sizeDelta = new Vector2(num, num2); Component val = FindTMPro(((Component)__instance).gameObject, "Description"); if ((Object)(object)val != (Object)null && (Object)(object)scrollContainer == (Object)null) { GameObject gameObject = val.gameObject; scrollContainer = new GameObject("ModScrollContainer"); scrollContainer.transform.SetParent(gameObject.transform.parent, false); ScrollRect val2 = scrollContainer.AddComponent(); RectTransform component2 = scrollContainer.GetComponent(); component2.anchorMin = new Vector2(0.05f, 0.25f); component2.anchorMax = new Vector2(0.95f, 0.88f); Vector2 offsetMin = (component2.offsetMax = Vector2.zero); component2.offsetMin = offsetMin; GameObject val3 = new GameObject("Viewport"); val3.transform.SetParent(scrollContainer.transform, false); RectTransform val4 = val3.AddComponent(); val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.one; val4.sizeDelta = Vector2.zero; ((Graphic)val3.AddComponent()).color = new Color(0.05f, 0.05f, 0.05f, 0.9f); val3.AddComponent().showMaskGraphic = true; gameObject.transform.SetParent(val3.transform, false); RectTransform component3 = gameObject.GetComponent(); component3.anchorMin = new Vector2(0f, 1f); component3.anchorMax = new Vector2(1f, 1f); component3.pivot = new Vector2(0.5f, 1f); component3.offsetMin = new Vector2(20f, 0f); component3.offsetMax = new Vector2(-20f, 0f); (gameObject.GetComponent() ?? gameObject.AddComponent()).verticalFit = (FitMode)2; val2.content = component3; val2.viewport = val4; val2.horizontal = false; val2.vertical = true; val2.scrollSensitivity = 35f; Il2CppReferenceArray val5 = Resources.FindObjectsOfTypeAll(Il2CppType.Of()); if (val5 != null && ((Il2CppArrayBase)(object)val5).Length > 0) { Scrollbar component4 = Object.Instantiate(((Component)((Il2CppObjectBase)((Il2CppArrayBase)(object)val5)[0]).Cast()).gameObject, scrollContainer.transform).GetComponent(); component4.direction = (Direction)2; RectTransform component5 = ((Component)component4).GetComponent(); component5.anchorMin = new Vector2(1f, 0f); component5.anchorMax = new Vector2(1f, 1f); component5.pivot = new Vector2(1f, 0.5f); component5.sizeDelta = new Vector2(25f, 0f); component5.anchoredPosition = Vector2.zero; val2.verticalScrollbar = component4; } } Button val6 = ((IEnumerable