Decompiled source of SaveSlots v1.1.0

SaveSlots.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace WhiteKnuckleSaveSlots;

[BepInPlugin("com.sondar.saveslots", "SaveSlots", "1.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class SaveSlotsPlugin : BaseUnityPlugin
{
	public struct SlotInfo
	{
		public int SlotNumber;

		public bool Exists;

		public string AreaName;

		public string CustomName;

		public DateTime LastModified;

		public long FileSizeBytes;
	}

	public static SaveSlotsPlugin Instance;

	public static ManualLogSource PluginLogger;

	public static ConfigEntry<int> ConfigCurrentSlot;

	public static ConfigEntry<int> ConfigTotalSlots;

	public static ConfigEntry<bool> ConfigShowHUD;

	public static ConfigEntry<KeyCode> ConfigManagerKey;

	public static ConfigEntry<bool> ConfigAutoBackups;

	public static ConfigEntry<int> ConfigMaxBackups;

	public static ConfigEntry<string>[] ConfigSlotNames = new ConfigEntry<string>[10];

	public static int CurrentSlot = 1;

	private static bool showManagerWindow = false;

	private static bool showBackupsView = false;

	private static Rect managerWindowRect = new Rect(100f, 70f, 580f, 510f);

	private static Vector2 backupScrollPos = Vector2.zero;

	private static string statusMessage = "";

	private static float statusMessageTimer = 0f;

	private static int renamingSlot = -1;

	private static string renameInputText = "";

	private static GUIStyle panelBoxStyle;

	private static GUIStyle activeSlotButtonStyle;

	private static GUIStyle inactiveSlotButtonStyle;

	private static GUIStyle titleLabelStyle;

	private static GUIStyle subtextLabelStyle;

	private static GUIStyle hudBoxStyle;

	private static GUIStyle hudTextStyle;

	private static bool stylesInitialized = false;

	public static int MaxSlots
	{
		get
		{
			if (ConfigTotalSlots != null)
			{
				return Mathf.Clamp(ConfigTotalSlots.Value, 2, 10);
			}
			return 5;
		}
	}

	private void Awake()
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Expected O, but got Unknown
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Expected O, but got Unknown
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Expected O, but got Unknown
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Expected O, but got Unknown
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f3: Expected O, but got Unknown
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Expected O, but got Unknown
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Expected O, but got Unknown
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Expected O, but got Unknown
		Instance = this;
		PluginLogger = ((BaseUnityPlugin)this).Logger;
		ConfigTotalSlots = ((BaseUnityPlugin)this).Config.Bind<int>("General", "TotalSlots", 5, new ConfigDescription("Number of available save slots (between 2 and 10)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), new object[0]));
		ConfigCurrentSlot = ((BaseUnityPlugin)this).Config.Bind<int>("General", "CurrentSlot", 1, new ConfigDescription("Currently active save slot (1 to MaxSlots)", (AcceptableValueBase)null, new object[0]));
		ConfigShowHUD = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHUD", true, new ConfigDescription("Show current slot indicator on HUD during gameplay", (AcceptableValueBase)null, new object[0]));
		ConfigManagerKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ManagerKey", (KeyCode)289, new ConfigDescription("Hotkey to toggle Save Slots Manager window", (AcceptableValueBase)null, new object[0]));
		ConfigAutoBackups = ((BaseUnityPlugin)this).Config.Bind<bool>("Backups", "EnableAutoBackups", true, new ConfigDescription("Automatically create safety backups before saving, copying, or deleting", (AcceptableValueBase)null, new object[0]));
		ConfigMaxBackups = ((BaseUnityPlugin)this).Config.Bind<int>("Backups", "MaxBackupsPerSlot", 5, new ConfigDescription("Max number of automatic backups kept per slot", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[0]));
		for (int i = 0; i < 10; i++)
		{
			int num = i + 1;
			ConfigSlotNames[i] = ((BaseUnityPlugin)this).Config.Bind<string>("Slot Names", "Slot" + num + "Name", "", new ConfigDescription("Custom display name for Slot " + num, (AcceptableValueBase)null, new object[0]));
		}
		CurrentSlot = Mathf.Clamp(ConfigCurrentSlot.Value, 1, MaxSlots);
		ConfigTotalSlots.SettingChanged += OnTotalSlotsChanged;
		MigrateLegacySaves();
		Harmony val = new Harmony("com.sondar.saveslots");
		val.PatchAll(typeof(SaveManagerPatches));
		PluginLogger.LogInfo((object)$"SaveSlots mod v1.1.0 loaded! Active Slot: {CurrentSlot} / Total Slots: {MaxSlots}");
	}

	private void OnTotalSlotsChanged(object sender, EventArgs e)
	{
		if (CurrentSlot > MaxSlots)
		{
			SetSlot(MaxSlots);
		}
	}

	private void Update()
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		if (statusMessageTimer > 0f)
		{
			statusMessageTimer -= Time.unscaledDeltaTime;
			if (statusMessageTimer <= 0f)
			{
				statusMessage = "";
			}
		}
		if (Input.GetKeyDown(ConfigManagerKey.Value))
		{
			showManagerWindow = !showManagerWindow;
		}
	}

	public static string GetSlotCustomName(int slot)
	{
		if (slot >= 1 && slot <= 10 && ConfigSlotNames[slot - 1] != null)
		{
			return ConfigSlotNames[slot - 1].Value.Trim();
		}
		return "";
	}

	public static void SetSlotCustomName(int slot, string newName)
	{
		if (slot >= 1 && slot <= 10 && ConfigSlotNames[slot - 1] != null)
		{
			ConfigSlotNames[slot - 1].Value = ((newName != null) ? newName.Trim() : "");
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Config.Save();
			}
		}
	}

	public static void SetSlot(int newSlot)
	{
		if (newSlot < 1 || newSlot > MaxSlots)
		{
			return;
		}
		CurrentSlot = newSlot;
		ConfigCurrentSlot.Value = newSlot;
		PluginLogger.LogInfo((object)("[SaveSlots] Active slot changed to: " + CurrentSlot));
		if (!((Object)(object)UI_GamemodeScreen.instance != (Object)null))
		{
			return;
		}
		try
		{
			UI_GamemodeScreen.instance.RefreshCurrentGamemode();
		}
		catch (Exception ex)
		{
			PluginLogger.LogError((object)("[SaveSlots] Error refreshing gamemode screen: " + ex));
		}
	}

	public static void ShowStatus(string msg, float duration = 3.5f)
	{
		statusMessage = msg;
		statusMessageTimer = duration;
	}

	public static string GetSessionsDirectory()
	{
		string text = Path.Combine(Application.persistentDataPath, "Sessions");
		if (!Directory.Exists(text))
		{
			try
			{
				Directory.CreateDirectory(text);
			}
			catch
			{
			}
		}
		return text;
	}

	public static string GetBackupsDirectory()
	{
		string text = Path.Combine(GetSessionsDirectory(), "Backups");
		if (!Directory.Exists(text))
		{
			try
			{
				Directory.CreateDirectory(text);
			}
			catch
			{
			}
		}
		return text;
	}

	private static void MigrateLegacySaves()
	{
		try
		{
			string sessionsDirectory = GetSessionsDirectory();
			string[] files = Directory.GetFiles(sessionsDirectory, "*-save.session");
			string[] array = files;
			foreach (string text in array)
			{
				string fileName = Path.GetFileName(text);
				if (!fileName.Contains("_slot"))
				{
					string text2 = fileName.Replace("-save.session", "");
					string text3 = Path.Combine(sessionsDirectory, text2 + "_slot1-save.session");
					if (!File.Exists(text3))
					{
						File.Copy(text, text3, overwrite: false);
						PluginLogger.LogInfo((object)$"[SaveSlots] Migrated legacy save '{fileName}' to '{Path.GetFileName(text3)}'");
					}
				}
			}
		}
		catch (Exception ex)
		{
			PluginLogger.LogError((object)("[SaveSlots] Error migrating legacy saves: " + ex));
		}
	}

	public static void CreateBackup(string baseFileName, int slot, string reason)
	{
		if (ConfigAutoBackups == null || !ConfigAutoBackups.Value)
		{
			return;
		}
		try
		{
			string slotFilePath = GetSlotFilePath(baseFileName, slot);
			if (File.Exists(slotFilePath))
			{
				string backupsDirectory = GetBackupsDirectory();
				string text = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
				string text2 = $"{baseFileName}_slot{slot}_{reason}_{text}.session";
				string destFileName = Path.Combine(backupsDirectory, text2);
				File.Copy(slotFilePath, destFileName, overwrite: true);
				PluginLogger.LogInfo((object)$"[SaveSlots] Auto-backup created: {text2}");
				PruneOldBackups(baseFileName, slot);
			}
		}
		catch (Exception ex)
		{
			PluginLogger.LogError((object)("[SaveSlots] Failed to create auto-backup: " + ex));
		}
	}

	private static void PruneOldBackups(string baseFileName, int slot)
	{
		try
		{
			string backupsDirectory = GetBackupsDirectory();
			string text = $"{baseFileName}_slot{slot}_";
			string[] files = Directory.GetFiles(backupsDirectory, text + "*.session");
			int num = ((ConfigMaxBackups != null) ? Mathf.Clamp(ConfigMaxBackups.Value, 1, 10) : 5);
			if (files.Length <= num)
			{
				return;
			}
			Array.Sort(files, (string a, string b) => File.GetCreationTime(a).CompareTo(File.GetCreationTime(b)));
			int num2 = files.Length - num;
			for (int num3 = 0; num3 < num2; num3++)
			{
				try
				{
					File.Delete(files[num3]);
				}
				catch
				{
				}
			}
		}
		catch
		{
		}
	}

	public static List<string> GetBackupsList(string baseFileName, int slot)
	{
		List<string> list = new List<string>();
		try
		{
			string backupsDirectory = GetBackupsDirectory();
			string text = $"{baseFileName}_slot{slot}_";
			string[] files = Directory.GetFiles(backupsDirectory, text + "*.session");
			Array.Sort(files, (string a, string b) => File.GetLastWriteTime(b).CompareTo(File.GetLastWriteTime(a)));
			list.AddRange(files);
		}
		catch
		{
		}
		return list;
	}

	public static bool RestoreBackup(string backupFilePath, string baseFileName, int targetSlot)
	{
		try
		{
			if (!File.Exists(backupFilePath))
			{
				return false;
			}
			CreateBackup(baseFileName, targetSlot, "pre_restore");
			string slotFilePath = GetSlotFilePath(baseFileName, targetSlot);
			File.Copy(backupFilePath, slotFilePath, overwrite: true);
			PluginLogger.LogInfo((object)$"[SaveSlots] Restored backup '{Path.GetFileName(backupFilePath)}' to Slot {targetSlot}");
			return true;
		}
		catch (Exception ex)
		{
			PluginLogger.LogError((object)("[SaveSlots] Error restoring backup: " + ex));
			return false;
		}
	}

	public static string GetSlotFileName(string baseFileName, int slot)
	{
		if (string.IsNullOrEmpty(baseFileName))
		{
			return baseFileName;
		}
		if (baseFileName.Contains("_slot"))
		{
			return baseFileName;
		}
		return baseFileName + "_slot" + slot;
	}

	public static string GetSlotFilePath(string baseFileName, int slot)
	{
		string sessionsDirectory = GetSessionsDirectory();
		string slotFileName = GetSlotFileName(baseFileName, slot);
		return Path.Combine(sessionsDirectory, slotFileName + "-save.session");
	}

	public static bool SlotExists(string baseFileName, int slot)
	{
		string slotFilePath = GetSlotFilePath(baseFileName, slot);
		return File.Exists(slotFilePath);
	}

	public static string GetCurrentGamemodeBaseName()
	{
		string text = "campaign";
		bool flag = false;
		try
		{
			if ((Object)(object)UI_GamemodeScreen.instance != (Object)null)
			{
				M_Gamemode gamemode = UI_GamemodeScreen.instance.GetGamemode();
				if ((Object)(object)gamemode != (Object)null)
				{
					text = gamemode.GetGamemodeName(false);
					flag = gamemode.IsHardMode();
				}
			}
			else if ((Object)(object)CL_GameManager.gamemode != (Object)null)
			{
				text = CL_GameManager.GetGamemodeName(false, false);
				flag = CL_GameManager.IsHardmode();
			}
		}
		catch
		{
		}
		string text2 = (flag ? "-hardmode" : "");
		return (text + text2).ToLower();
	}

	public static SlotInfo GetSlotInfo(string baseFileName, int slot)
	{
		SlotInfo result = new SlotInfo
		{
			SlotNumber = slot,
			Exists = false,
			AreaName = "Empty",
			CustomName = GetSlotCustomName(slot),
			LastModified = DateTime.MinValue,
			FileSizeBytes = 0L
		};
		string slotFilePath = GetSlotFilePath(baseFileName, slot);
		if (File.Exists(slotFilePath))
		{
			result.Exists = true;
			try
			{
				FileInfo fileInfo = new FileInfo(slotFilePath);
				result.LastModified = fileInfo.LastWriteTime;
				result.FileSizeBytes = fileInfo.Length;
				using FileStream stream = new FileStream(slotFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				using GZipStream stream2 = new GZipStream(stream, CompressionMode.Decompress);
				using StreamReader streamReader = new StreamReader(stream2, Encoding.UTF8);
				string text = streamReader.ReadToEnd();
				SessionSave val = JsonUtility.FromJson<SessionSave>(text);
				if (val != null && !string.IsNullOrEmpty(val.saveName))
				{
					result.AreaName = val.saveName;
				}
				else
				{
					result.AreaName = "Saved Run";
				}
			}
			catch
			{
				result.AreaName = "Occupied";
			}
		}
		return result;
	}

	public static bool CopySlotData(string baseFileName, int fromSlot, int toSlot)
	{
		if (fromSlot == toSlot)
		{
			return false;
		}
		string slotFilePath = GetSlotFilePath(baseFileName, fromSlot);
		if (!File.Exists(slotFilePath))
		{
			return false;
		}
		if (SlotExists(baseFileName, toSlot))
		{
			CreateBackup(baseFileName, toSlot, "pre_copy");
		}
		string slotFilePath2 = GetSlotFilePath(baseFileName, toSlot);
		try
		{
			File.Copy(slotFilePath, slotFilePath2, overwrite: true);
			string slotCustomName = GetSlotCustomName(fromSlot);
			if (!string.IsNullOrEmpty(slotCustomName) && string.IsNullOrEmpty(GetSlotCustomName(toSlot)))
			{
				SetSlotCustomName(toSlot, slotCustomName);
			}
			PluginLogger.LogInfo((object)$"[SaveSlots] Copied Slot {fromSlot} to Slot {toSlot}");
			return true;
		}
		catch (Exception ex)
		{
			PluginLogger.LogError((object)("[SaveSlots] Failed to copy slot: " + ex));
			return false;
		}
	}

	public static void DeleteSlotData(string baseFileName, int slot)
	{
		CreateBackup(baseFileName, slot, "deleted");
		string sessionsDirectory = GetSessionsDirectory();
		string slotFilePath = GetSlotFilePath(baseFileName, slot);
		if (File.Exists(slotFilePath))
		{
			try
			{
				File.Delete(slotFilePath);
			}
			catch
			{
			}
		}
		if (slot <= 1)
		{
			string path = Path.Combine(sessionsDirectory, baseFileName + "-save.session");
			if (File.Exists(path))
			{
				try
				{
					File.Delete(path);
				}
				catch
				{
				}
			}
		}
		PluginLogger.LogInfo((object)("[SaveSlots] Deleted save for slot " + slot));
	}

	private void InitStyles()
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: 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_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Expected O, but got Unknown
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Expected O, but got Unknown
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Expected O, but got Unknown
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01df: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e9: Expected O, but got Unknown
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Expected O, but got Unknown
		//IL_0267: Unknown result type (might be due to invalid IL or missing references)
		//IL_0286: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Expected O, but got Unknown
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d4: Expected O, but got Unknown
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		if (!stylesInitialized || panelBoxStyle == null)
		{
			Texture2D background = MakeTex(2, 2, new Color(0.05f, 0.08f, 0.07f, 0.94f));
			Texture2D background2 = MakeTex(2, 2, new Color(0.1f, 0.4f, 0.25f, 0.96f));
			Texture2D background3 = MakeTex(2, 2, new Color(0.1f, 0.14f, 0.13f, 0.92f));
			Texture2D background4 = MakeTex(2, 2, new Color(0.18f, 0.28f, 0.24f, 0.96f));
			panelBoxStyle = new GUIStyle(GUI.skin.box);
			panelBoxStyle.normal.background = background;
			panelBoxStyle.normal.textColor = new Color(0.4f, 0.9f, 0.6f);
			activeSlotButtonStyle = new GUIStyle(GUI.skin.button);
			activeSlotButtonStyle.normal.background = background2;
			activeSlotButtonStyle.normal.textColor = new Color(0.5f, 1f, 0.7f);
			activeSlotButtonStyle.fontStyle = (FontStyle)1;
			activeSlotButtonStyle.alignment = (TextAnchor)4;
			activeSlotButtonStyle.hover.background = background2;
			activeSlotButtonStyle.hover.textColor = Color.white;
			inactiveSlotButtonStyle = new GUIStyle(GUI.skin.button);
			inactiveSlotButtonStyle.normal.background = background3;
			inactiveSlotButtonStyle.normal.textColor = new Color(0.75f, 0.85f, 0.8f);
			inactiveSlotButtonStyle.alignment = (TextAnchor)4;
			inactiveSlotButtonStyle.hover.background = background4;
			inactiveSlotButtonStyle.hover.textColor = Color.white;
			titleLabelStyle = new GUIStyle(GUI.skin.label);
			titleLabelStyle.fontStyle = (FontStyle)1;
			titleLabelStyle.fontSize = 12;
			titleLabelStyle.normal.textColor = new Color(0.4f, 1f, 0.6f);
			titleLabelStyle.alignment = (TextAnchor)4;
			subtextLabelStyle = new GUIStyle(GUI.skin.label);
			subtextLabelStyle.fontSize = 11;
			subtextLabelStyle.normal.textColor = new Color(0.7f, 0.8f, 0.75f);
			subtextLabelStyle.alignment = (TextAnchor)3;
			hudBoxStyle = new GUIStyle(GUI.skin.box);
			hudBoxStyle.normal.background = MakeTex(2, 2, new Color(0.04f, 0.07f, 0.05f, 0.85f));
			hudTextStyle = new GUIStyle(GUI.skin.label);
			hudTextStyle.alignment = (TextAnchor)4;
			hudTextStyle.fontSize = 11;
			hudTextStyle.fontStyle = (FontStyle)1;
			hudTextStyle.normal.textColor = new Color(0.45f, 1f, 0.65f);
			stylesInitialized = true;
		}
	}

	private Texture2D MakeTex(int width, int height, Color col)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		Color[] array = (Color[])(object)new Color[width * height];
		for (int i = 0; i < array.Length; i++)
		{
			array[i] = col;
		}
		Texture2D val = new Texture2D(width, height);
		val.SetPixels(array);
		val.Apply();
		return val;
	}

	private void OnGUI()
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Expected O, but got Unknown
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		InitStyles();
		if ((Object)(object)UI_GamemodeScreen.instance != (Object)null && ((Component)UI_GamemodeScreen.instance).gameObject.activeInHierarchy)
		{
			DrawMainMenuSlotSelector();
		}
		if (ConfigShowHUD.Value && (Object)(object)CL_GameManager.gMan != (Object)null && !CL_GameManager.runHasEnded)
		{
			DrawInGameHUD();
		}
		if (showManagerWindow)
		{
			managerWindowRect = GUI.Window(987654, managerWindowRect, new WindowFunction(DrawManagerWindow), "SAVE SLOTS MANAGER");
		}
	}

	private void DrawMainMenuSlotSelector()
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0252: Unknown result type (might be due to invalid IL or missing references)
		int maxSlots = MaxSlots;
		float num = ((maxSlots > 6) ? 75f : 125f);
		float num2 = Mathf.Clamp((float)maxSlots * num + 60f, 740f, (float)Screen.width - 40f);
		float num3 = 82f;
		float num4 = ((float)Screen.width - num2) / 2f;
		float num5 = 20f;
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(num4, num5, num2, num3);
		GUI.Box(val, "", panelBoxStyle);
		string currentGamemodeBaseName = GetCurrentGamemodeBaseName();
		Rect val2 = default(Rect);
		((Rect)(ref val2))..ctor(num4, num5 + 4f, num2 - 100f, 20f);
		GUI.Label(val2, $"— SAVE SLOTS [1 - {maxSlots}] —", titleLabelStyle);
		string arg = ((object)ConfigManagerKey.Value).ToString();
		Rect val3 = default(Rect);
		((Rect)(ref val3))..ctor(num4 + num2 - 95f, num5 + 4f, 85f, 18f);
		if (GUI.Button(val3, $"Menu [{arg}]"))
		{
			showManagerWindow = !showManagerWindow;
		}
		float num6 = (num2 - 30f) / (float)maxSlots;
		float num7 = 48f;
		float num8 = num4 + 15f;
		float num9 = num5 + 26f;
		Rect val4 = default(Rect);
		for (int i = 1; i <= maxSlots; i++)
		{
			SlotInfo slotInfo = GetSlotInfo(currentGamemodeBaseName, i);
			((Rect)(ref val4))..ctor(num8 + (float)(i - 1) * num6, num9, num6 - 4f, num7);
			bool flag = i == CurrentSlot;
			GUIStyle val5 = (flag ? activeSlotButtonStyle : inactiveSlotButtonStyle);
			string customName = slotInfo.CustomName;
			string text = (string.IsNullOrEmpty(customName) ? (flag ? $"▶ SLOT {i} ◀" : $"SLOT {i}") : (flag ? $"▶ {customName} ◀" : customName));
			string text2 = (slotInfo.Exists ? slotInfo.AreaName : "(Empty)");
			int num10 = ((maxSlots > 6) ? 10 : 16);
			if (text.Length > num10)
			{
				text = text.Substring(0, num10 - 2) + "..";
			}
			if (text2.Length > num10)
			{
				text2 = text2.Substring(0, num10 - 2) + "..";
			}
			string text3 = $"{text}\n{text2}";
			if (GUI.Button(val4, text3, val5) && CurrentSlot != i)
			{
				SetSlot(i);
			}
		}
		if (!string.IsNullOrEmpty(statusMessage))
		{
			Rect val6 = default(Rect);
			((Rect)(ref val6))..ctor(num4, num5 + num3 + 4f, num2, 22f);
			GUI.Box(val6, statusMessage, panelBoxStyle);
		}
	}

	private void DrawInGameHUD()
	{
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0098: Unknown result type (might be due to invalid IL or missing references)
		string slotCustomName = GetSlotCustomName(CurrentSlot);
		string text = (string.IsNullOrEmpty(slotCustomName) ? $"SAVE SLOT: #{CurrentSlot}" : $"SLOT #{CurrentSlot}: {slotCustomName}");
		float num = Mathf.Max(145f, (float)text.Length * 8f + 20f);
		float num2 = 26f;
		float num3 = (float)Screen.width - num - 16f;
		float num4 = 16f;
		Rect val = default(Rect);
		((Rect)(ref val))..ctor(num3, num4, num, num2);
		GUI.Box(val, "", hudBoxStyle);
		GUI.Label(val, text, hudTextStyle);
	}

	private void DrawManagerWindow(int windowID)
	{
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		string currentGamemodeBaseName = GetCurrentGamemodeBaseName();
		int maxSlots = MaxSlots;
		GUILayout.Space(6f);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label($"Mode: <b>{currentGamemodeBaseName.ToUpper()}</b> | Slot: <b>#{CurrentSlot}</b> | Slots: <b>{maxSlots}</b>", titleLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		string text = (showBackupsView ? "Slots View" : "Backups");
		if (GUILayout.Button(text, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.Width(90f),
			GUILayout.Height(22f)
		}))
		{
			showBackupsView = !showBackupsView;
		}
		GUILayout.EndHorizontal();
		GUILayout.Space(4f);
		if (showBackupsView)
		{
			DrawBackupsSection(currentGamemodeBaseName);
		}
		else
		{
			DrawSlotsSection(currentGamemodeBaseName, maxSlots);
		}
		GUILayout.Space(6f);
		string text2 = $"Close [{ConfigManagerKey.Value}]";
		if (GUILayout.Button(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }))
		{
			renamingSlot = -1;
			showManagerWindow = false;
		}
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 25f));
	}

	private void DrawSlotsSection(string baseName, int total)
	{
		for (int i = 1; i <= total; i++)
		{
			SlotInfo slotInfo = GetSlotInfo(baseName, i);
			bool flag = i == CurrentSlot;
			GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
			string text = (flag ? "<color=#00FF88><b>[ACTIVE]</b></color> " : "");
			string text2 = ((!string.IsNullOrEmpty(slotInfo.CustomName)) ? $" (\"{slotInfo.CustomName}\")" : "");
			string text3 = (slotInfo.Exists ? string.Format("{0}Slot {1}{2}: <color=white><b>{3}</b></color> ({4})", text, i, text2, slotInfo.AreaName, slotInfo.LastModified.ToString("MMM dd HH:mm")) : $"{text}Slot {i}{text2}: <color=grey>(Empty)</color>");
			if (renamingSlot == i)
			{
				GUILayout.Label($"Slot {i} Name:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(85f) });
				renameInputText = GUILayout.TextField(renameInputText, 24, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
				if (GUILayout.Button("Save", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) }))
				{
					SetSlotCustomName(i, renameInputText);
					renamingSlot = -1;
					ShowStatus($"Slot {i} renamed.");
				}
				if (GUILayout.Button("Cancel", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) }))
				{
					renamingSlot = -1;
				}
			}
			else
			{
				GUILayout.Label(text3, subtextLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (GUILayout.Button("Rename", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(62f) }))
				{
					renamingSlot = i;
					renameInputText = GetSlotCustomName(i);
				}
				if (!flag && GUILayout.Button("Select", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }))
				{
					SetSlot(i);
				}
				if (slotInfo.Exists && GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }))
				{
					DeleteSlotData(baseName, i);
					if ((Object)(object)UI_GamemodeScreen.instance != (Object)null)
					{
						UI_GamemodeScreen.instance.RefreshCurrentGamemode();
					}
					ShowStatus($"Slot {i} deleted (backup created).");
				}
			}
			GUILayout.EndHorizontal();
		}
		GUILayout.Space(6f);
		GUILayout.BeginVertical(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("Quick Slot Copy:", titleLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label($"Copy Slot {CurrentSlot} to Slot:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) });
		for (int j = 1; j <= total; j++)
		{
			if (j == CurrentSlot || !GUILayout.Button(j.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(32f) }))
			{
				continue;
			}
			if (CopySlotData(baseName, CurrentSlot, j))
			{
				ShowStatus($"Slot {CurrentSlot} copied to Slot {j}!");
				if ((Object)(object)UI_GamemodeScreen.instance != (Object)null)
				{
					UI_GamemodeScreen.instance.RefreshCurrentGamemode();
				}
			}
			else
			{
				ShowStatus("Copy failed: current slot has no save data.");
			}
		}
		GUILayout.EndHorizontal();
		GUILayout.EndVertical();
	}

	private void DrawBackupsSection(string baseName)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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)
		GUILayout.Label($"Auto-Backups for Active Slot {CurrentSlot}:", titleLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		List<string> backupsList = GetBackupsList(baseName, CurrentSlot);
		backupScrollPos = GUILayout.BeginScrollView(backupScrollPos, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(280f) });
		if (backupsList.Count == 0)
		{
			GUILayout.Label("<color=grey>No backups found for this slot yet. Backups are created automatically before saves, copies, and deletions.</color>", subtextLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
		else
		{
			foreach (string item in backupsList)
			{
				FileInfo fileInfo = new FileInfo(item);
				string name = fileInfo.Name;
				string arg = string.Format("{0} ({1})", fileInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss"), fileInfo.Length / 1024 + " KB");
				GUILayout.BeginHorizontal(GUIStyle.op_Implicit("box"), (GUILayoutOption[])(object)new GUILayoutOption[0]);
				GUILayout.Label($"<b>{name}</b>\n<color=#88CCAA>{arg}</color>", subtextLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
				if (GUILayout.Button("Restore", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(75f),
					GUILayout.Height(30f)
				}) && RestoreBackup(item, baseName, CurrentSlot))
				{
					ShowStatus($"Backup restored to Slot {CurrentSlot}!");
					if ((Object)(object)UI_GamemodeScreen.instance != (Object)null)
					{
						UI_GamemodeScreen.instance.RefreshCurrentGamemode();
					}
				}
				if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(60f),
					GUILayout.Height(30f)
				}))
				{
					try
					{
						File.Delete(item);
					}
					catch
					{
					}
				}
				GUILayout.EndHorizontal();
			}
		}
		GUILayout.EndScrollView();
	}
}
public static class SaveManagerPatches
{
	[HarmonyPatch(typeof(CL_SaveManager), "SaveSessionToFile")]
	[HarmonyPrefix]
	public static void SaveSessionToFile_Prefix(SessionSave data, ref string fileName)
	{
		if (!fileName.Contains("_slot"))
		{
			string arg = fileName;
			SaveSlotsPlugin.CreateBackup(fileName, SaveSlotsPlugin.CurrentSlot, "autosave");
			fileName = SaveSlotsPlugin.GetSlotFileName(fileName, SaveSlotsPlugin.CurrentSlot);
			SaveSlotsPlugin.PluginLogger.LogInfo((object)$"[SaveSlots] SaveSessionToFile: '{arg}' -> '{fileName}'");
		}
	}

	[HarmonyPatch(typeof(CL_SaveManager), "LoadSessionFromFile")]
	[HarmonyPrefix]
	public static void LoadSessionFromFile_Prefix(ref string fileName)
	{
		if (!fileName.Contains("_slot"))
		{
			string arg = fileName;
			fileName = SaveSlotsPlugin.GetSlotFileName(fileName, SaveSlotsPlugin.CurrentSlot);
			SaveSlotsPlugin.PluginLogger.LogInfo((object)$"[SaveSlots] LoadSessionFromFile: '{arg}' -> '{fileName}'");
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(CL_SaveManager), "DeleteSessionSave")]
	public static bool DeleteSessionSave_Prefix(string gamemodeName, bool hardmode)
	{
		string text = (hardmode ? "-hardmode" : "");
		string text2 = gamemodeName.ToLower() + text;
		SaveSlotsPlugin.PluginLogger.LogInfo((object)$"[SaveSlots] DeleteSessionSave for slot {SaveSlotsPlugin.CurrentSlot} (base: {text2})");
		SaveSlotsPlugin.DeleteSlotData(text2, SaveSlotsPlugin.CurrentSlot);
		return false;
	}
}