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;
}
}