using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("MoreSaveSlots")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("raddude")]
[assembly: AssemblyProduct("MoreSaveSlots")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(true)]
[assembly: Guid("071994df-c696-4ece-ad36-48d4036214b5")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace MoreSaveSlots;
internal class Configs
{
internal static ConfigEntry<int> numPages;
internal static void InitializeConfigs()
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Expected O, but got Unknown
ConfigFile config = ((BaseUnityPlugin)MSS_Plugin.Instance).Config;
numPages = config.Bind<int>("Settings", "Number of save slot pages<br>(must restart game)", 3, new ConfigDescription("The number of pages of save slots. Each page has 6 slots.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
}
}
internal static class Extensions
{
public static T GetPrivateField<T>(this object obj, string field)
{
return (T)Traverse.Create(obj).Field(field).GetValue();
}
public static void SetPrivateField(this object obj, string field, object value)
{
Traverse.Create(obj).Field(field).SetValue(value);
}
public static void SetPrivateField<T>(string field, object value)
{
Traverse.Create(typeof(T)).Field(field).SetValue(value);
}
public static object InvokePrivateMethod(this object obj, string method, params object[] parameters)
{
return AccessTools.Method(obj.GetType(), method, (Type[])null, (Type[])null).Invoke(obj, parameters);
}
}
[BepInPlugin("com.raddude.moresaveslots", "MoreSaveSlots", "1.0.0")]
public class MSS_Plugin : BaseUnityPlugin
{
public const string PLUGIN_GUID = "com.raddude.moresaveslots";
public const string PLUGIN_NAME = "MoreSaveSlots";
public const string PLUGIN_VERSION = "1.0.0";
private static ManualLogSource _logger;
internal static MSS_Plugin Instance { get; private set; }
internal static void LogDebug(string message)
{
_logger.LogDebug((object)message);
}
internal static void LogInfo(string message)
{
_logger.LogInfo((object)message);
}
internal static void LogWarning(string message)
{
_logger.LogWarning((object)message);
}
internal static void LogError(string message)
{
_logger.LogError((object)message);
}
private void Awake()
{
if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
{
Object.Destroy((Object)(object)((Component)this).gameObject);
return;
}
Instance = this;
_logger = ((BaseUnityPlugin)this).Logger;
Configs.InitializeConfigs();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "com.raddude.moresaveslots");
}
}
internal class Paginator
{
internal const int SLOTS_PER_PAGE = 6;
private static int _currentPage = 0;
private static readonly List<GameObject> _allSlotRoots = new List<GameObject>();
private static BackupSavesListUI _backUpSavesListUI;
public static void AddMoreSaveSlots(BackupSavesListUI backupSavesListUI, StartMenuButton[] existingButtons)
{
_backUpSavesListUI = backupSavesListUI;
List<StartMenuButton> list = (from b in existingButtons
where (int)b.GetPrivateField<StartMenuButtonType>("type") == 8
orderby b.saveSlot
select b).ToList();
foreach (StartMenuButton item in list)
{
_allSlotRoots.Add(((Component)((Component)item).transform.parent).gameObject);
}
for (int i = 6; i < 6 * Configs.numPages.Value; i++)
{
int index = i % 6;
GameObject val = _allSlotRoots[index];
GameObject val2 = Object.Instantiate<GameObject>(val, val.transform.parent);
((Object)val2).name = $"SaveSlot_{i}";
StartMenuButton componentInChildren = val2.GetComponentInChildren<StartMenuButton>();
if ((Object)(object)componentInChildren != (Object)null)
{
componentInChildren.saveSlot = i;
RefreshSlotText(componentInChildren);
}
val2.SetActive(false);
_allSlotRoots.Add(val2);
}
}
private static void RefreshSlotText(StartMenuButton btn)
{
if (SaveSlots.slotsActive != null && btn.saveSlot < SaveSlots.slotsActive.Length && SaveSlots.slotsActive[btn.saveSlot])
{
DateTime lastWriteTime = File.GetLastWriteTime(SaveSlots.GetSlotSavePath(btn.saveSlot));
btn.SetButtonText(lastWriteTime.ToShortTimeString() + "\n" + lastWriteTime.ToShortDateString());
}
else
{
btn.SetButtonText("(empty)");
}
}
public static bool ButtonClick(StartMenuButtonType button)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0004: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Invalid comparison between Unknown and I4
if ((int)button == 13)
{
_backUpSavesListUI.HideList();
_currentPage = Mathf.Max(0, _currentPage - 1);
SaveSlotsUI.UpdatePageNumText(_currentPage);
ShowPage(_currentPage);
return false;
}
if ((int)button == 14)
{
_backUpSavesListUI.HideList();
_currentPage = Mathf.Min(Configs.numPages.Value - 1, _currentPage + 1);
SaveSlotsUI.UpdatePageNumText(_currentPage);
ShowPage(_currentPage);
return false;
}
return true;
}
private static void ShowPage(int page)
{
foreach (GameObject allSlotRoot in _allSlotRoots)
{
allSlotRoot.SetActive(false);
}
_currentPage = page;
int num = page * 6;
int num2 = Mathf.Min(num + 6, 6 * Configs.numPages.Value);
for (int i = num; i < num2; i++)
{
_allSlotRoots[i].SetActive(true);
}
}
}
internal class SaveMenuPatches
{
[HarmonyPatch(typeof(SaveSlots), "Awake")]
private class SaveSlotsPatches
{
public static bool Prefix()
{
SaveSlots.slotsActive = new bool[6 * Configs.numPages.Value];
for (int i = 0; i < SaveSlots.slotsActive.Length; i++)
{
SaveSlots.currentSlot = i;
if (File.Exists(SaveSlots.GetCurrentSavePath()))
{
SaveSlots.slotsActive[i] = true;
SaveSlots.activeSlotsCount++;
}
}
MSS_Plugin.LogDebug("SaveSlots: activeSlotsCount is " + SaveSlots.activeSlotsCount);
return false;
}
}
[HarmonyPatch(typeof(StartMenu))]
private class StartMenuPatches
{
[HarmonyBefore(new string[] { "com.nandbrew.nandtweaks" })]
[HarmonyPostfix]
[HarmonyPatch("Start")]
public static void InitializeSaveSlotsUI(StartMenu __instance, GameObject ___saveSlotUI)
{
SaveSlotsUI.InitializeUI(___saveSlotUI);
Paginator.AddMoreSaveSlots(__instance.backupSavesUI, ___saveSlotUI.GetComponentsInChildren<StartMenuButton>(true));
}
[HarmonyPrefix]
[HarmonyPatch("ButtonClick", new Type[] { typeof(StartMenuButtonType) })]
public static bool ButtonClickPatch(StartMenuButtonType button)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return Paginator.ButtonClick(button);
}
}
[HarmonyPatch(typeof(BackupSavesListUI))]
private class BackupSavesListUIPatches
{
[HarmonyPrefix]
[HarmonyPatch("ShowList")]
public static bool ShowList(StartMenuButton parentSlotButton, BackupSavesListUI __instance, ref int ___showingListFor)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
if (___showingListFor == parentSlotButton.saveSlot)
{
return false;
}
___showingListFor = parentSlotButton.saveSlot;
bool active = false;
((Component)__instance).transform.position = ((Component)parentSlotButton).transform.parent.position;
if (parentSlotButton.saveSlot % 6 <= 2)
{
((Component)__instance).transform.Translate(Vector3.up * __instance.topRowOffset);
}
StartMenuButton[] buttons = __instance.buttons;
StartMenuButton[] array = buttons;
foreach (StartMenuButton val in array)
{
string backupPath = SaveSlots.GetBackupPath(parentSlotButton.saveSlot, val.saveSlot);
if (File.Exists(backupPath))
{
active = true;
DateTime lastWriteTime = File.GetLastWriteTime(backupPath);
string buttonText = lastWriteTime.ToShortTimeString() + "\n" + lastWriteTime.ToShortDateString();
val.SetButtonText(buttonText);
((Component)((Component)val).transform.parent).gameObject.SetActive(true);
}
else
{
((Component)((Component)val).transform.parent).gameObject.SetActive(false);
}
}
((Component)__instance.list).gameObject.SetActive(active);
return false;
}
[HarmonyPrefix]
[HarmonyPatch("Update")]
public static bool Update(BackupSavesListUI __instance, int ___showingListFor, Vector3 ___backButtonInitialPos, Vector3 ___backButtonAltPos)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)__instance.currentLookedAtSlot == (Object)null))
{
__instance.ShowList(__instance.currentLookedAtSlot);
}
Vector3 val;
if (___showingListFor % 6 == 4 && ((Component)__instance.list).gameObject.activeInHierarchy)
{
((Component)SaveSlotsUI.PageNumTextMesh).gameObject.SetActive(false);
val = ___backButtonAltPos;
}
else
{
((Component)SaveSlotsUI.PageNumTextMesh).gameObject.SetActive(true);
val = ___backButtonInitialPos;
}
__instance.backButton.parent.localPosition = Vector3.Lerp(__instance.backButton.parent.localPosition, val, Time.deltaTime * 8f);
if (___showingListFor % 6 == 1 && ((Component)__instance.list).gameObject.activeInHierarchy)
{
__instance.chooseSlotText.SetActive(false);
}
else
{
__instance.chooseSlotText.SetActive(true);
}
return false;
}
}
}
internal class SaveSlotsUI
{
internal const StartMenuButtonType PREVIOUS_BUTTON = 13;
internal const StartMenuButtonType NEXT_BUTTON = 14;
internal static TextMesh PageNumTextMesh { get; private set; }
internal static void InitializeUI(GameObject saveSlotUI)
{
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0210: 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)
saveSlotUI.transform.GetChild(12).localPosition = new Vector3(1.157f, 1.12f, 0.033f);
Transform val = Object.Instantiate<Transform>(saveSlotUI.transform.GetChild(10));
((Object)val).name = "previous button";
val.SetParent(saveSlotUI.transform);
val.localPosition = new Vector3(-1.45f, 0.5f, 0f);
val.localEulerAngles = new Vector3(0f, 180f, 0f);
val.localScale = new Vector3(1f, 1f, 1f);
((Component)val.GetChild(1)).GetComponent<TextMesh>().text = "Previous";
((Component)val.GetChild(2)).GetComponent<TextMesh>().text = "←";
((Component)val.GetChild(0)).GetComponent<StartMenuButton>().SetPrivateField("type", (object)(StartMenuButtonType)13);
Transform val2 = Object.Instantiate<Transform>(saveSlotUI.transform.GetChild(10));
((Object)val2).name = "next button";
val2.SetParent(saveSlotUI.transform);
val2.localPosition = new Vector3(1.45f, 0.5f, 0f);
val2.localEulerAngles = new Vector3(0f, 180f, 0f);
val2.localScale = new Vector3(1f, 1f, 1f);
((Component)val2.GetChild(1)).GetComponent<TextMesh>().text = "Next";
((Component)val2.GetChild(2)).GetComponent<TextMesh>().text = "→";
((Component)val2.GetChild(0)).GetComponent<StartMenuButton>().SetPrivateField("type", (object)(StartMenuButtonType)14);
Transform val3 = Object.Instantiate<Transform>(saveSlotUI.transform.GetChild(3));
((Object)val3).name = "page num text";
val3.SetParent(saveSlotUI.transform);
val3.localPosition = new Vector3(0f, 0.5f, 0f);
val3.localEulerAngles = new Vector3(0f, 0f, 0f);
val3.localScale = new Vector3(0.0165f, 0.0177f, 0.0177f);
PageNumTextMesh = ((Component)val3).GetComponent<TextMesh>();
PageNumTextMesh.text = "page 1";
}
internal static void UpdatePageNumText(int pageNum)
{
PageNumTextMesh.text = $"page {pageNum + 1}";
}
}