using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SaveTheWindows")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.0")] [module: UnverifiableCode] namespace SaveTheWindows; public enum ESortOrder { NameAsc, NameDesc, DateAsc, DateDesc, SizeAsc, SizeDesc } [BepInPlugin("starfi5h.plugin.SaveTheWindows", "SaveTheWindows", "1.1.2")] public class Plugin : BaseUnityPlugin { public const string GUID = "starfi5h.plugin.SaveTheWindows"; public const string NAME = "SaveTheWindows"; public const string VERSION = "1.1.2"; public static ManualLogSource Log; public static ConfigFile ConfigFile; public static ConfigEntry SubFolder; public static ConfigEntry SaveOrder; private static Harmony harmony; public void Awake() { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ConfigFile = ((BaseUnityPlugin)this).Config; ConfigEntry obj = ((BaseUnityPlugin)this).Config.Bind("Config", "Enable Save Window Position", true, "启用窗口位置保存"); ConfigEntry val = ((BaseUnityPlugin)this).Config.Bind("Config", "Enable Drag Window Offset", true, "允许窗口部分超出边框"); ConfigEntry val2 = ((BaseUnityPlugin)this).Config.Bind("Config", "Enable Save Subfolder", true, "允许存档子文件夹功能"); SubFolder = ((BaseUnityPlugin)this).Config.Bind("Config", "Save Subfolder", "", "Name of the current subfolder\n当前存档子文件夹名称(空字串=原位置)"); SaveOrder = ((BaseUnityPlugin)this).Config.Bind("Config", "Save Order", ESortOrder.NameAsc, "Sort order of save files.\n存档排序的方式"); SaveOrder.SettingChanged += delegate { SaveFolder_Patch.OnSaveOrderChange(); }; harmony = new Harmony("starfi5h.plugin.SaveTheWindows"); if (obj.Value) { harmony.PatchAll(typeof(SaveWindow_Patch)); } if (val.Value) { harmony.PatchAll(typeof(UIWindowDragOffset_Patch)); } if (val2.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Save subfolder enable. Name:" + SubFolder.Value)); harmony.PatchAll(typeof(SaveFolder_Patch)); } } } public class SaveFolder_Patch { private static string subfolder = ""; private static GameObject group; private static UIComboBox subfolderComboBox; private static UIComboBox orderComboBox; [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public static void GetGameSaveSubfolder(ref string __result) { if (!string.IsNullOrEmpty(subfolder)) { if (!__result.EndsWith("/")) { __result += "/"; } __result = __result + subfolder + "/"; } } public static void OnOrderComboBoxIndexChange() { if (orderComboBox.itemIndex >= 0 && orderComboBox.itemIndex < orderComboBox.Items.Count) { Plugin.SaveOrder.Value = (ESortOrder)orderComboBox.itemIndex; Plugin.Log.LogDebug((object)("Change order to " + Plugin.SaveOrder.Value)); } } public static void OnSaveOrderChange() { if (((ManualBehaviour)UIRoot.instance.loadGameWindow).active) { UIRoot.instance.loadGameWindow.RefreshList(); } if (((ManualBehaviour)UIRoot.instance.saveGameWindow).active) { UIRoot.instance.saveGameWindow.RefreshList(); } } [HarmonyPostfix] [HarmonyPriority(200)] [HarmonyPatch(typeof(UILoadGameWindow), "RefreshList")] [HarmonyPatch(typeof(UISaveGameWindow), "RefreshList")] private static void RefreshList(List ___entries) { if (Plugin.SaveOrder.Value == ESortOrder.NameAsc) { return; } List list = new List(); for (int num = ___entries.Count - 1; num >= 0; num--) { UIGameSaveEntry val = ___entries[num]; if (val.indexText.text != "") { list.Add(val); ___entries.RemoveAt(num); } } switch (Plugin.SaveOrder.Value) { case ESortOrder.NameDesc: list.Sort((UIGameSaveEntry x, UIGameSaveEntry y) => -string.Compare(x.fileInfo.Name, y.fileInfo.Name)); break; case ESortOrder.DateAsc: list.Sort((UIGameSaveEntry x, UIGameSaveEntry y) => DateTime.Compare(x.fileInfo.LastWriteTime, y.fileInfo.LastWriteTime)); break; case ESortOrder.DateDesc: list.Sort((UIGameSaveEntry x, UIGameSaveEntry y) => -DateTime.Compare(x.fileInfo.LastWriteTime, y.fileInfo.LastWriteTime)); break; case ESortOrder.SizeAsc: list.Sort((UIGameSaveEntry x, UIGameSaveEntry y) => (int)(x.fileInfo.Length - y.fileInfo.Length)); break; case ESortOrder.SizeDesc: list.Sort((UIGameSaveEntry x, UIGameSaveEntry y) => -(int)(x.fileInfo.Length - y.fileInfo.Length)); break; } int num2 = ___entries.Count; for (int i = 1; i <= list.Count; i++) { UIGameSaveEntry val2 = list[i - 1]; val2.SetEntry(++num2, i, val2.fileInfo); ___entries.Add(val2); } } [HarmonyPrefix] [HarmonyPatch(typeof(UIMainMenu), "_OnOpen")] public static void Init() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown if ((Object)(object)group != (Object)null) { return; } try { GameObject gameObject = ((Component)((Component)UIRoot.instance.optionWindow.resolutionComp).transform).gameObject; group = new GameObject("Subfolder_Group"); GameObject val = Object.Instantiate(gameObject, group.transform, false); ((Object)val).name = "Subfolder ComboBox"; val.transform.localPosition = new Vector3(0f, 0f, 0f); Transform val2 = val.transform.Find("Dropdown List ScrollBox/Mask/Content Panel/"); for (int num = val2.childCount - 1; num >= 0; num--) { if (((Object)val2.GetChild(num)).name == "Item Button(Clone)") { Object.Destroy((Object)(object)((Component)val2.GetChild(num)).gameObject); } } subfolderComboBox = val.GetComponentInChildren(); ((UnityEventBase)subfolderComboBox.onItemIndexChange).RemoveAllListeners(); subfolderComboBox.DropDownCount = 25; subfolderComboBox.itemIndex = 0; RefreshSubfolderComboBoxList(); ((UnityEvent)subfolderComboBox.onItemIndexChange).AddListener(new UnityAction(OnSubfolderComboBoxIndexChange)); SetGameSaveSubfolder(Plugin.SubFolder.Value); Plugin.Log.LogDebug((object)"UI Subfolder init"); GameObject obj = Object.Instantiate(val, group.transform, false); ((Object)obj).name = "Order ComboBox"; obj.transform.localPosition = new Vector3(320f, 0f, 0f); orderComboBox = obj.GetComponentInChildren(); ((UnityEventBase)orderComboBox.onItemIndexChange).RemoveAllListeners(); orderComboBox.DropDownCount = 6; orderComboBox.Items.Clear(); orderComboBox.ItemsData.Clear(); orderComboBox.Items.AddRange(new string[6] { "Name (Asc)", "Name (Desc)", "Date (Asc)", "Date (Desc)", "Size (Asc)", "Size (Desc)" }); orderComboBox.ItemsData.AddRange(new int[6] { 0, 1, 2, 3, 4, 5 }); orderComboBox.itemIndex = (int)Plugin.SaveOrder.Value; ((UnityEvent)orderComboBox.onItemIndexChange).AddListener(new UnityAction(OnOrderComboBoxIndexChange)); } catch (Exception ex) { Plugin.Log.LogWarning((object)"Error when creating subfolder UI!"); Plugin.Log.LogWarning((object)ex); } } [HarmonyPrefix] [HarmonyPriority(600)] [HarmonyPatch(typeof(UILoadGameWindow), "_OnOpen")] private static void SetSubfolderGroupPosition(UILoadGameWindow __instance) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)group == (Object)null) { Init(); } try { group.transform.SetParent(((Component)__instance.showButton).transform.parent); group.transform.localPosition = ((Component)__instance.showButton).transform.localPosition + new Vector3(0f, -45f, 0f); group.transform.localScale = Vector3.one; RefreshSubfolderComboBoxList(); } catch (Exception ex) { Plugin.Log.LogError((object)ex); } } [HarmonyPrefix] [HarmonyPriority(600)] [HarmonyPatch(typeof(UISaveGameWindow), "_OnOpen")] private static void SetSubfolderGroupPosition(UISaveGameWindow __instance) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)group == (Object)null) { Init(); } try { group.transform.SetParent(((Component)__instance.showButton).transform.parent); group.transform.localPosition = ((Component)__instance.showButton).transform.localPosition + new Vector3(0f, -45f, 0f); group.transform.localScale = Vector3.one; RefreshSubfolderComboBoxList(); } catch (Exception ex) { Plugin.Log.LogError((object)ex); } } public static void OnDestroy() { Object.Destroy((Object)(object)group); } public static void SetGameSaveSubfolder(string folderName) { if (subfolder != folderName) { Plugin.Log.LogDebug((object)("SetGameSaveSubfolder " + folderName)); Plugin.SubFolder.Value = (subfolder = folderName); if ((Object)(object)UIRoot.instance != (Object)null) { if (((ManualBehaviour)UIRoot.instance.loadGameWindow).active) { UIRoot.instance.loadGameWindow.RefreshList(); } if (((ManualBehaviour)UIRoot.instance.saveGameWindow).active) { UIRoot.instance.saveGameWindow.RefreshList(); } } } if (!string.IsNullOrEmpty(subfolder) && !Directory.Exists(GameConfig.gameSaveFolder)) { Plugin.Log.LogInfo((object)("CreateDirectory " + GameConfig.gameSaveFolder)); Directory.CreateDirectory(GameConfig.gameSaveFolder); } } public static void OnSubfolderComboBoxIndexChange() { if (subfolderComboBox.itemIndex >= 0 && subfolderComboBox.itemIndex < subfolderComboBox.Items.Count) { SetGameSaveSubfolder(subfolderComboBox.Items[subfolderComboBox.itemIndex]); } else { SetGameSaveSubfolder(""); } } private static void RefreshSubfolderComboBoxList() { subfolderComboBox.Items.Clear(); subfolderComboBox.ItemsData.Clear(); bool flag = false; List list = new List(Directory.EnumerateDirectories(GameConfig.gameSavePath)); list.Insert(0, ""); for (int i = 0; i < list.Count; i++) { string fileName = Path.GetFileName(list[i]); subfolderComboBox.Items.Add(fileName); subfolderComboBox.ItemsData.Add(i); if (fileName == subfolder) { subfolderComboBox.itemIndex = i; flag = true; } } if (!flag) { subfolderComboBox.itemIndex = 0; } } } public class SaveWindow_Patch { private static readonly List _windows = new List(); [HarmonyPostfix] [HarmonyPatch(typeof(UIRoot), "OpenGameUI")] public static void OpenGameUI() { CollectWindows(); LoadWindowPos(); } [HarmonyPostfix] [HarmonyPatch(typeof(GameMain), "End")] public static void OnGameEnd() { SaveWindowPos(); } private static void CollectWindows() { Transform val = ((Component)UIRoot.instance.overlayCanvas).transform.Find("In Game/Windows"); if ((Object)(object)val != (Object)null) { _windows.Clear(); ((Component)val).GetComponentsInChildren(true, _windows); Plugin.Log.LogInfo((object)$"Collect {_windows.Count} windows"); } else { Plugin.Log.LogWarning((object)"Can't find In Game/Windows"); } } private static void LoadWindowPos() { //IL_0042: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) foreach (UIWindowDrag window in _windows) { if (!((Object)(object)window?.dragTrans == (Object)null)) { string name = ((Object)window).name; RectTransform dragTrans = window.dragTrans; Vector2 value = Plugin.ConfigFile.Bind("Window Position", name, Vector2.zero, (ConfigDescription)null).Value; if (!(value == Vector2.zero)) { dragTrans.anchoredPosition = value; } } } } private static void SaveWindowPos() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) Vector2 value = default(Vector2); foreach (UIWindowDrag window in _windows) { if (!((Object)(object)window?.dragTrans == (Object)null)) { string name = ((Object)window).name; RectTransform dragTrans = window.dragTrans; ((Vector2)(ref value))..ctor((float)Mathf.RoundToInt(dragTrans.anchoredPosition.x), (float)Mathf.RoundToInt(dragTrans.anchoredPosition.y)); Plugin.ConfigFile.Bind("Window Position", name, Vector2.zero, (ConfigDescription)null).Value = value; } } } } public class UIWindowDragOffset_Patch { [HarmonyTranspiler] [HarmonyPatch(typeof(UIWindowDrag), "Update")] public static IEnumerable UIWindowDrag_Update_Transpiler(IEnumerable instructions) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown try { return new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction i) => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "WorldToScreenPoint"), (string)null) }).RemoveInstruction().InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(UIWindowDragOffset_Patch), "WorldToScreenPoint_Min", (Type[])null, (Type[])null)) }) .MatchForward(false, (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((Func)((CodeInstruction i) => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "WorldToScreenPoint"), (string)null) }) .RemoveInstruction() .InsertAndAdvance((CodeInstruction[])(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(UIWindowDragOffset_Patch), "WorldToScreenPoint_Max", (Type[])null, (Type[])null)) }) .InstructionEnumeration(); } catch (Exception ex) { Plugin.Log.LogError((object)"Transpiler UIWindowDrag.Update error"); Plugin.Log.LogError((object)ex); return instructions; } } private static Vector2 WorldToScreenPoint_Min(Vector3 worldPos, UIWindowDrag window) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Vector2 val = UIRoot.WorldToScreenPoint(worldPos); Rect rect = window.refTrans.rect; float num = ((Rect)(ref rect)).width * 3f / 4f; rect = window.refTrans.rect; return val + new Vector2(num, ((Rect)(ref rect)).height - 60f); } private static Vector2 WorldToScreenPoint_Max(Vector3 worldPos, UIWindowDrag window) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) Vector2 val = UIRoot.WorldToScreenPoint(worldPos); Rect rect = window.refTrans.rect; float num = ((Rect)(ref rect)).width * 3f / 4f; rect = window.refTrans.rect; return val - new Vector2(num, ((Rect)(ref rect)).height - 60f); } }