using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AssetBundleTools;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Data.Sqlite;
using SaveSelectPlugin;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Util;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("Celestial Corp")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.6.0")]
[assembly: AssemblyInformationalVersion("1.0.6+a962c6c4be43b13d7bced6210a9d636b0018f9db")]
[assembly: AssemblyProduct("SaveSelectPlugin")]
[assembly: AssemblyTitle("SaveSelectPlugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.6.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
[HarmonyPatch]
public class BiosMenuPatch
{
[HarmonyPatch(typeof(BiosMenu), "Start")]
private class StartPatch
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static UnityAction <>9__0_0;
public static Func<SavePanelItem, bool> <>9__1_0;
internal void <Postfix>b__0_0()
{
OnAddSaveClick();
}
internal bool <OnAddSaveClick>b__1_0(SavePanelItem x)
{
return x.isNewSave;
}
}
private static void Postfix(BiosMenu __instance)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
GameObject obj = Object.Instantiate<GameObject>(BundleTool.GetPrefab("Assets/SaveSelectPlugin/SavePanel.prefab"), GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame").transform);
((Object)obj).name = "SavePanel";
obj.AddComponent<SavePanel>();
ButtonClickedEvent onClick = ((Component)obj.transform.Find("ScrollView/Viewport/Content/AddSave")).GetComponent<Button>().onClick;
object obj2 = <>c.<>9__0_0;
if (obj2 == null)
{
UnityAction val = delegate
{
OnAddSaveClick();
};
<>c.<>9__0_0 = val;
obj2 = (object)val;
}
((UnityEvent)onClick).AddListener((UnityAction)obj2);
}
private static void OnAddSaveClick()
{
SavePanel component = GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame/SavePanel").GetComponent<SavePanel>();
if (component.items.Count <= 0 || component.items.FirstOrDefault((SavePanelItem x) => x.isNewSave) == null)
{
component.items.Add(new SavePanelItem(null, selected: true));
}
}
}
[HarmonyPatch(typeof(BiosMenu), "OnSelectSinglePlayer")]
private class OnSelectSinglePlayerPatch
{
private static void Postfix(BiosMenu __instance)
{
GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame/InfoDeletePlayer").SetActive(false);
Animator component = ((Component)Object.FindObjectOfType<SavePanel>(true)).gameObject.GetComponent<Animator>();
component.ResetTrigger("Reset");
component.SetTrigger("SlideIn");
}
}
[HarmonyPatch(typeof(BiosMenu), "OnSelectOnlineMode")]
private class OnSelectOnlineModePatch
{
private static void Postfix(BiosMenu __instance)
{
GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame/InfoDeletePlayer").SetActive(true);
}
}
[HarmonyPatch(typeof(BiosMenu), "OnBackOnlineMode")]
private class OnBackOnlineModePatch
{
private static void Postfix(BiosMenu __instance)
{
GameObject gameObject = ((Component)Object.FindObjectOfType<SavePanel>(true)).gameObject;
if ((Object)(object)gameObject != (Object)null)
{
gameObject.GetComponent<Animator>().SetTrigger("Reset");
}
}
}
[HarmonyPatch(typeof(BiosMenu), "OnSinglePlayer")]
private class OnSinglePlayerPatch
{
private static bool Prefix(BiosMenu __instance)
{
SavePanel component = GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame/SavePanel").GetComponent<SavePanel>();
if (component.items != null && component.items.Count > 0)
{
SavePanelItem savePanelItem = component.items.First((SavePanelItem x) => x.isSelected.isOn);
if (savePanelItem != null)
{
PlayerPrefs.SetInt("user_force_gameover", savePanelItem.shouldWipe.isOn ? 1 : 0);
GameSave save = savePanelItem._save;
if (save == null)
{
if (!savePanelItem.GenSave())
{
__instance.panelsOptions[6].SetActive(true);
__instance.connect_text.text = "Error: Snapshot name cannot be blank!";
__instance.objBackButtonConn.SetActive(true);
return false;
}
return true;
}
new MyDatabase();
if (!DataUtils.CheckVersion(save.FilePath, out var error))
{
__instance.panelsOptions[6].SetActive(true);
__instance.connect_text.text = "Error: " + error;
__instance.objBackButtonConn.SetActive(true);
MyDatabase.Singleton = null;
return false;
}
MyDatabase.Singleton = null;
DataUtils.lastSave = save.FileName;
DataUtils.SaveGreyDbName();
if (!save.Current)
{
DataUtils.LoadGame(save.FilePath);
}
return true;
}
__instance.panelsOptions[6].SetActive(true);
__instance.connect_text.text = "Error: No snapshot selected!";
__instance.objBackButtonConn.SetActive(true);
return false;
}
return true;
}
}
}
[HarmonyPatch]
public class MenuInicioPatch
{
[HarmonyPatch(typeof(MenuInicio), "OnClickOpenMenu")]
private class OnClickOpenMenuPatch
{
private static void Postfix()
{
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Expected O, but got Unknown
if (Networking.IsSinglePlayer() && (Object)(object)save == (Object)null)
{
GameObject help = GameObject.Find("MenuInicio/Help");
save = Object.Instantiate<GameObject>(help, help.transform.parent);
((Object)save).name = "Snapshot";
Transform obj = save.transform.Find("Image");
Object.DestroyImmediate((Object)(object)((Component)obj).GetComponent<Image>());
Image obj2 = ((Component)obj).gameObject.AddComponent<Image>();
obj2.sprite = BundleTool.GetSprite("Assets/SaveSelectPlugin/snapshot.png");
((Graphic)obj2).color = Color.black;
Button component = save.GetComponent<Button>();
ColorBlock colors = ((Selectable)component).colors;
Object.DestroyImmediate((Object)(object)component);
Button obj3 = save.AddComponent<Button>();
((Selectable)obj3).colors = colors;
((UnityEvent)obj3.onClick).AddListener((UnityAction)delegate
{
((Component)help.transform.parent).gameObject.SetActive(false);
DataUtils.LoadGreyDbName();
DataUtils.SaveGame(DataUtils.lastSave);
OS.ShowError("Saved snapshot \"" + DataUtils.lastSave + "\"!");
});
Transform obj4 = save.transform.Find("TextMeshPro Text");
Object.DestroyImmediate((Object)(object)((Component)obj4).GetComponent<ItemUITranslation>());
((TMP_Text)((Component)obj4).GetComponent<TextMeshProUGUI>()).text = "Snapshot";
}
}
}
public static GameObject save;
}
namespace SaveSelectPlugin
{
public class DataUtils
{
public static string lastSave;
private static string saveFolder = Path.Combine(Application.dataPath, "Saves");
public static void SaveGreyDbName()
{
File.WriteAllText(Path.Combine(saveFolder, "LastDb.txt"), lastSave);
}
public static void LoadGreyDbName()
{
string path = Path.Combine(saveFolder, "LastDb.txt");
if (File.Exists(path))
{
lastSave = File.ReadAllText(path);
}
}
public static string GetPathFromName(string fileName)
{
return Path.Combine(saveFolder, fileName + ".db");
}
public static List<GameSave> GetSaves()
{
CheckSaveFolder();
List<GameSave> list = new List<GameSave>();
GameSave currentSave = GetCurrentSave();
if (currentSave != null)
{
list.Add(currentSave);
}
string[] files = Directory.GetFiles(saveFolder, "*.db");
foreach (string path in files)
{
list.Add(new GameSave(path));
}
if (list.Count == 0)
{
return null;
}
return list;
}
public static GameSave GetCurrentSave()
{
string path = Path.Combine(Application.dataPath, "GreyHackDB.db");
if (File.Exists(path))
{
GameSave gameSave = new GameSave(path);
gameSave.Current = true;
LoadGreyDbName();
if (!string.IsNullOrEmpty(lastSave))
{
gameSave.FileName = lastSave;
}
return gameSave;
}
return null;
}
public static GameSave NewGame(string fileName)
{
CheckSaveFolder();
string path = Path.Combine(Application.dataPath, "GreyHackDB.db");
if (File.Exists(path))
{
try
{
File.Delete(path);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex.ToString());
}
}
return new GameSave(GetPathFromName(fileName));
}
public static void LoadGame(string filePath)
{
CheckSaveFolder();
try
{
File.Copy(filePath, Path.Combine(Application.dataPath, "GreyHackDB.db"), overwrite: true);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex.ToString());
}
}
public static void SaveGame(string fileName)
{
CheckSaveFolder();
string sourceFileName = Path.Combine(Application.dataPath, "GreyHackDB.db");
try
{
File.Copy(sourceFileName, GetPathFromName(fileName), overwrite: true);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex.ToString());
}
}
public static void DeleteSave(string fileName, bool current = false)
{
CheckSaveFolder();
string path = GetPathFromName(fileName);
if (current)
{
path = Path.Combine(Application.dataPath, "GreyHackDB.db");
}
try
{
File.Delete(path);
}
catch (Exception ex)
{
Plugin.Logger.LogError((object)ex.ToString());
}
}
private static void CheckSaveFolder()
{
if (!Directory.Exists(saveFolder))
{
Directory.CreateDirectory(saveFolder);
}
}
public static bool CheckVersion(string savePath, out string error)
{
int num = (int)(AccessTools.TypeByName("Util.GameConfig")?.GetField("VersionDeleteDB", BindingFlags.Static | BindingFlags.Public)).GetValue(null);
error = "";
int dbVersion = MyDatabase.Singleton.GetDbVersion(savePath);
if (num != dbVersion)
{
error = $"This save is not for this version of the game!\nClientDB: v{num} - SaveDB: v{dbVersion}";
return false;
}
return true;
}
}
public class GameSave
{
public bool Current { get; set; }
public string FilePath { get; set; }
public string FileName { get; set; }
public DateTime Created { get; set; }
public DateTime LastSave { get; set; }
public GameSave(string path)
{
FilePath = path;
FileName = Path.GetFileNameWithoutExtension(path);
if (File.Exists(path))
{
Created = File.GetCreationTime(path);
LastSave = File.GetLastWriteTime(path);
}
}
}
public class MyDatabase
{
public enum IdDatabase
{
MYSQL,
SQLITE
}
private interface IGreyReader
{
bool Read();
string GetString(int i);
int GetInt32(int i);
float GetFloat(int i);
void Close();
}
private class WrapperSqliteReader : IGreyReader
{
private IDataReader reader;
public WrapperSqliteReader(IDataReader reader)
{
this.reader = reader;
}
public bool Read()
{
return reader.Read();
}
public string GetString(int i)
{
return reader.GetString(i);
}
public int GetInt32(int i)
{
return reader.GetInt32(i);
}
public float GetFloat(int i)
{
return reader.GetFloat(i);
}
public void Close()
{
reader.Close();
}
}
private interface IGreyDB : IDisposable
{
IGreyReader ExecuteReader();
IGreyReader ExecuteReader(string query);
object ExecuteScalar();
object ExecuteScalar(string query);
void ExecuteNonQuery();
void ExecuteNonQuery(string nonQuery);
void AddParameter(string name, string value);
void AddParameter(string name, int value);
void AddParameter(string name, float value);
bool ExistValue();
void ClearParameters();
}
private class ConfigSqlite : IGreyDB, IDisposable
{
private IDbConnection connection;
private IDbCommand command;
private IDataReader reader;
public ConfigSqlite(string query, string dbName)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected O, but got Unknown
connection = (IDbConnection)new SqliteConnection(dbName);
connection.Open();
command = connection.CreateCommand();
command.CommandText = query;
}
public IGreyReader ExecuteReader()
{
if (reader != null)
{
reader.Close();
}
reader = command.ExecuteReader();
return new WrapperSqliteReader(reader);
}
public IGreyReader ExecuteReader(string query)
{
if (reader != null)
{
reader.Close();
}
command.CommandText = query;
return ExecuteReader();
}
public object ExecuteScalar()
{
return command.ExecuteScalar();
}
public object ExecuteScalar(string query)
{
if (reader != null)
{
reader.Close();
}
command.CommandText = query;
return ExecuteScalar();
}
public void ExecuteNonQuery()
{
command.ExecuteNonQuery();
}
public void ExecuteNonQuery(string nonQuery)
{
command.CommandText = nonQuery;
command.ExecuteNonQuery();
}
public void AddParameter(string name, string value)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Expected O, but got Unknown
command.Parameters.Add((object?)new SqliteParameter(name, (object)value));
}
public void AddParameter(string name, int value)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
command.Parameters.Add((object?)new SqliteParameter(name, (object)value));
}
public void AddParameter(string name, float value)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Expected O, but got Unknown
command.Parameters.Add((object?)new SqliteParameter(name, (object)value));
}
public bool ExistValue()
{
return Convert.ToInt32(command.ExecuteScalar()) >= 1;
}
public void ClearParameters()
{
command.Parameters.Clear();
}
public void Dispose()
{
if (reader != null)
{
reader.Dispose();
reader = null;
}
if (command != null)
{
command.Dispose();
command = null;
}
if (connection != null)
{
connection.Dispose();
connection = null;
}
GC.SuppressFinalize(this);
}
}
public static MyDatabase Singleton;
public string dbName;
private IdDatabase idDatabase = IdDatabase.SQLITE;
public MyDatabase()
{
idDatabase = IdDatabase.SQLITE;
dbName = "URI=file:" + Application.dataPath + "/GreyHackDB.db;";
Singleton = this;
}
private IGreyDB Config(string query)
{
return new ConfigSqlite(query, dbName);
}
public int GetDbVersion(string filePath)
{
dbName = "URI=file:" + filePath;
string text = "SELECT count(*) FROM sqlite_master WHERE type='table' and name='InfoGen';";
string text2 = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'GreyHackDB' AND table_name = 'InfoGen';";
string query = ((idDatabase == IdDatabase.MYSQL) ? text2 : text);
int result = 0;
using (IGreyDB greyDB = Config(query))
{
if (greyDB.ExistValue())
{
query = "SELECT DeleteVersion FROM InfoGen WHERE DeleteVersion IS NOT NULL;";
IGreyReader greyReader = greyDB.ExecuteReader(query);
if (greyReader.Read())
{
result = greyReader.GetInt32(0);
}
}
}
return result;
}
}
[BepInPlugin("com.machaceleste.saveselectplugin", "SaveSelectPlugin", "1.0.6")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
private void Awake()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"Plugin SaveSelectPlugin is loaded!");
BundleTool.LoadBundle();
new Harmony("com.machaceleste.saveselectplugin").PatchAll();
}
}
public class SavePanel : MonoBehaviour
{
public List<SavePanelItem> items;
private List<GameSave> saves;
public SavePanel()
{
items = new List<SavePanelItem>();
saves = DataUtils.GetSaves();
if (saves == null)
{
return;
}
foreach (GameSave safe in saves)
{
items.Add(new SavePanelItem(safe));
}
}
}
public class SavePanelItem
{
public Toggle isSelected;
public Toggle shouldWipe;
public GameSave _save;
public bool isNewSave = true;
private GameObject _saveItem;
private TMP_InputField _saveNameInputField;
private readonly string format = "MM/dd/yyyy HH:mm";
public SavePanelItem(GameSave save = null, bool selected = false)
{
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Expected O, but got Unknown
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
Transform transform = GameObject.Find("SavePanel/ScrollView/Viewport/Content").transform;
GameObject val = GameObject.Find("SavePanel/ScrollView/Viewport/Content/SaveTemplate");
_saveItem = Object.Instantiate<GameObject>(val, transform);
_saveItem.SetActive(true);
GameObject.Find("SavePanel/ScrollView/Viewport/Content/AddSave").transform.SetAsLastSibling();
isSelected = ((Component)_saveItem.transform.Find("Top/Select")).GetComponent<Toggle>();
if (selected)
{
isSelected.isOn = true;
}
_saveNameInputField = ((Component)_saveItem.transform.Find("Top/NameInput")).GetComponent<TMP_InputField>();
shouldWipe = ((Component)_saveItem.transform.Find("Top/Wipe")).GetComponent<Toggle>();
((UnityEvent)((Component)_saveItem.transform.Find("Top/Delete")).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
{
OnDeleteWorldClicked();
});
if (save != null)
{
isNewSave = false;
_save = save;
_saveNameInputField.text = save.FileName;
((Selectable)_saveNameInputField).interactable = false;
if (_save.Current)
{
((Graphic)((Component)((Component)isSelected).transform.Find("Background")).GetComponent<Image>()).color = Color.red;
}
((TMP_Text)((Component)_saveItem.transform.Find("Bottom/DateCreated")).GetComponent<TextMeshProUGUI>()).text = _save.Created.ToString(format);
((TMP_Text)((Component)_saveItem.transform.Find("Bottom/DateSaved")).GetComponent<TextMeshProUGUI>()).text = _save.LastSave.ToString(format);
}
}
public bool GenSave()
{
string text = _saveNameInputField.text;
if (string.IsNullOrEmpty(text))
{
return false;
}
_save = DataUtils.NewGame(text);
DataUtils.lastSave = text;
DataUtils.SaveGreyDbName();
return true;
}
private void OnDeleteWorldClicked()
{
if (_save != null)
{
DataUtils.DeleteSave(_save.FileName, _save.Current);
}
Object.Destroy((Object)(object)_saveItem);
GameObject.Find("MainMenu/MainPanel/MidPanel/PanelGame/PanelOptions/PlayGame/SavePanel").GetComponent<SavePanel>().items.Remove(this);
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "SaveSelectPlugin";
public const string PLUGIN_NAME = "SaveSelectPlugin";
public const string PLUGIN_VERSION = "1.0.6";
}
}
namespace AssetBundleTools
{
public class BundleTool
{
public static AssetBundle bundle;
public static void LoadBundle()
{
string text = Path.Combine(Paths.PluginPath, Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "SaveSelectPlugin.bundle");
if (!File.Exists(text))
{
Debug.LogError((object)"[Info :SaveSelectPlugin] Bundle not found!");
return;
}
bundle = AssetBundle.LoadFromFile(text);
if ((Object)(object)bundle == (Object)null)
{
Debug.LogError((object)"[Info :SaveSelectPlugin] Failed to load bundle!");
}
else
{
Debug.Log((object)"[Info :SaveSelectPlugin] Loaded bundle");
}
}
public static GameObject GetPrefab(string path)
{
GameObject val = bundle.LoadAsset<GameObject>(path);
if ((Object)(object)val == (Object)null)
{
Debug.LogError((object)("[Info :SaveSelectPlugin] Failed to load prefab " + path));
return null;
}
return val;
}
public static AudioClip GetClip(string path)
{
AudioClip val = bundle.LoadAsset<AudioClip>(path);
if ((Object)(object)val == (Object)null)
{
Debug.LogError((object)("[Info :SaveSelectPlugin] Failed to load audio clip " + path));
return null;
}
return val;
}
public static Sprite GetSprite(string path)
{
Sprite val = bundle.LoadAsset<Sprite>(path);
if ((Object)(object)val == (Object)null)
{
Debug.LogError((object)("[Info :SaveSelectPlugin] Failed to load sprite " + path));
return null;
}
return val;
}
}
}