using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UI; using Zorro.Core; using Zorro.Core.Serizalization; using Zorro.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] [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; } } } namespace PEAKSaveManager { [BepInPlugin("com.lucasandersen.peakallyouneedsavemanager", "The All You Need Save Manager", "1.0.0")] public sealed class SaveManagerPlugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <>c__DisplayClass188_0 { public PlayerSnapshot snapshot; internal bool b__0(Player player) { PhotonView photonView = GetPhotonView((Component)(object)player); if ((Object)(object)photonView == (Object)null) { return false; } Player owner = photonView.Owner; if (snapshot.actorNumber > 0 && owner != null && owner.ActorNumber == snapshot.actorNumber) { return true; } if (owner != null) { return string.Equals(owner.NickName, snapshot.playerName, StringComparison.OrdinalIgnoreCase); } return false; } } [CompilerGenerated] private sealed class d__189 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Player player; public SaveManagerPlugin <>4__this; public PlayerSnapshot snapshot; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__189(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: return false; case 0: { <>1__state = -1; Character character = player.character; if ((Object)(object)character == (Object)null) { return false; } saveManagerPlugin.ApplyInventory(player, character, snapshot.inventory); saveManagerPlugin.ApplyCharacterSnapshot(character, snapshot.character); Vector3 val = snapshot.position.ToUnity(); PhotonView photonView = GetPhotonView((Component)(object)character); Player val2 = (((Object)(object)photonView != (Object)null) ? photonView.Owner : null); if ((Object)(object)photonView != (Object)null && val2 != null) { photonView.RPC("WarpPlayerRPC", val2, new object[2] { val, false }); } else { ((Component)character).transform.position = val; } if ((Object)(object)photonView != (Object)null && photonView.IsMine) { ((Component)character).transform.eulerAngles = snapshot.rotation.ToUnity(); character.data.lookValues = snapshot.character.lookValues.ToUnity(); RecalculateLookDirectionsMethod?.Invoke(character, null); } else if ((Object)(object)photonView == (Object)null) { ((Component)character).transform.eulerAngles = snapshot.rotation.ToUnity(); } ApplyCharacterVelocity(character, snapshot.velocity, snapshot.angularVelocity); ApplyEquippedSelection(player, character, snapshot.inventory); <>2__current = (object)new WaitForSeconds(0.05f); <>1__state = 1; return true; } case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__155 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Player <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; Player IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__155(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -3; } else { <>1__state = -1; Type type = AccessTools.TypeByName("PlayerHandler"); if (type == null) { return false; } MethodInfo methodInfo = AccessTools.Method(type, "GetAllPlayers", (Type[])null, (Type[])null); if (methodInfo == null) { return false; } object obj; try { obj = methodInfo.Invoke(null, null); } catch { return false; } if (!(obj is IEnumerable enumerable)) { goto IL_00d9; } <>7__wrap1 = enumerable.GetEnumerator(); <>1__state = -3; } while (<>7__wrap1.MoveNext()) { object current = <>7__wrap1.Current; Player val = (Player)((current is Player) ? current : null); if (val != null) { <>2__current = val; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = null; goto IL_00d9; IL_00d9: return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__155(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__185 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public string fullPath; private SaveEnvelope 5__2; private string 5__3; private int 5__4; private List.Enumerator <>7__wrap4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__185(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 4u) { try { if (num == -4 || num == 5) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } 5__2 = null; 5__3 = null; <>7__wrap4 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Expected O, but got Unknown bool result; try { int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; if (saveManagerPlugin.isLoading) { result = false; } else { saveManagerPlugin.isLoading = true; saveManagerPlugin.SetStatus("Loading save...", Color.cyan, 10f); <>1__state = -3; if (!TryReadSaveEnvelope(fullPath, out 5__2, out var reason)) { saveManagerPlugin.SetStatus("Incompatible save: " + reason, Color.yellow, 6f); result = false; break; } if (5__2.players.Count == 0) { saveManagerPlugin.SetStatus("Save file has no player snapshots.", Color.yellow, 6f); result = false; break; } if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { saveManagerPlugin.SetStatus("Only host can load shared saves.", Color.yellow, 4f); result = false; break; } 5__3 = ResolveTargetScene(5__2.metadata); bool flag = SaveNeedsNonAirportScene(5__2.metadata); if (string.IsNullOrWhiteSpace(5__3) && flag) { if (IsInAirportScene()) { saveManagerPlugin.SetStatus("Saved level is unavailable or mismatched for this version.", Color.yellow, 7f); result = false; break; } saveManagerPlugin.SetStatus("Saved level mismatch. Loading into current level.", Color.yellow, 5f); } int num2; if (!string.IsNullOrEmpty(5__3)) { Scene activeScene = SceneManager.GetActiveScene(); num2 = ((!string.Equals(((Scene)(ref activeScene)).name, 5__3, StringComparison.OrdinalIgnoreCase)) ? 1 : 0); } else { num2 = 0; } if (5__2.metadata.levelSeed != 0) { SetPendingSeedForLoad(5__2.metadata.levelSeed); ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Queued seed {PendingSeedForLoad.Value} for next level generation"); } else { ClearPendingSeedForLoad(); } if (num2 == 0) { Ascents.currentAscent = 5__2.metadata.ascent; goto IL_0274; } <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.LoadSceneRoutine(5__3, 5__2.metadata.ascent)); <>1__state = 1; result = true; } goto end_IL_0000; case 1: <>1__state = -3; if (!saveManagerPlugin.lastSceneLoadSucceeded) { saveManagerPlugin.SetStatus("Failed to load scene '" + 5__3 + "'.", Color.red, 6f); result = false; break; } goto IL_0274; case 2: { <>1__state = -3; if (saveManagerPlugin.CountMatchedPlayers(5__2.players) <= 0) { saveManagerPlugin.SetStatus("No matching players were found for this save.", Color.yellow, 6f); result = false; break; } if (!MapHandler.Exists) { goto IL_034d; } Segment val2 = ClampSegment(5__2.metadata.currentSegment); MapHandler val3 = Object.FindFirstObjectByType(); Segment val4 = (Segment)(((Object)(object)val3 != (Object)null) ? ((int)val3.GetCurrentSegment()) : 0); if ((int)val2 == 0 || val2 == val4) { goto IL_034d; } MapHandler.JumpToSegment(val2); <>2__current = (object)new WaitForSeconds(0.75f); <>1__state = 3; result = true; goto end_IL_0000; } case 3: <>1__state = -3; goto IL_034d; case 4: <>1__state = -3; 5__4 = 0; <>7__wrap4 = 5__2.players.GetEnumerator(); <>1__state = -4; goto IL_042e; case 5: { <>1__state = -4; 5__4++; goto IL_042e; } IL_042e: while (true) { if (<>7__wrap4.MoveNext()) { PlayerSnapshot current = <>7__wrap4.Current; Player val = saveManagerPlugin.FindPlayer(current); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)$"Could not find player for snapshot '{current.playerName}' (Actor: {current.actorNumber})"); continue; } <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.ApplyPlayerSnapshotRoutine(val, current)); <>1__state = 5; result = true; } else { <>m__Finally2(); <>7__wrap4 = default(List.Enumerator); if (5__4 <= 0) { saveManagerPlugin.SetStatus("Load finished but no players were restored.", Color.yellow, 6f); result = false; break; } saveManagerPlugin.RestoreRunMetadata(5__2.metadata); saveManagerPlugin.SetStatus($"Loaded save successfully ({5__4}/{5__2.players.Count} players).", Color.green, 4f); 5__2 = null; 5__3 = null; <>m__Finally1(); result = false; } goto end_IL_0000; } break; IL_034d: <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreWorldInteractablesRoutine(5__2)); <>1__state = 4; result = true; goto end_IL_0000; IL_0274: <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(WaitForPlayersRoutine(5__2.players, 20f)); <>1__state = 2; result = true; goto end_IL_0000; } <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; SaveManagerPlugin saveManagerPlugin = <>4__this; ClearPendingSeedForLoad(); saveManagerPlugin.isLoading = false; saveManagerPlugin.RefreshSaveFileList(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap4).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__186 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public int ascent; public string sceneName; private bool 5__2; private float 5__3; private AsyncOperation 5__4; private float 5__5; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__186(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; saveManagerPlugin.lastSceneLoadSucceeded = false; Ascents.currentAscent = ascent; try { GameHandler.AddStatus((GameStatus)new SceneSwitchingStatus()); } catch (Exception ex) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("Could not set scene switching status: " + ex.Message)); } 5__2 = false; try { LoadingScreenHandler instance = RetrievableResourceSingleton.Instance; if ((Object)(object)instance != (Object)null) { instance.Load((LoadingScreenType)1, (Action)null, new IEnumerator[1] { instance.LoadSceneProcess(sceneName, true, true, 0.5f) }); 5__2 = true; } } catch (Exception ex2) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("LoadingScreenHandler load failed, using fallback load: " + ex2.Message)); } if (!5__2) { 5__4 = SceneManager.LoadSceneAsync(sceneName); if (5__4 == null) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)("Could not start fallback scene load for '" + sceneName + "'.")); return false; } 5__5 = 45f; goto IL_0144; } goto IL_0165; case 1: <>1__state = -1; goto IL_0144; case 2: { <>1__state = -1; break; } IL_0165: 5__3 = 45f; break; IL_0144: if (!5__4.isDone && 5__5 > 0f) { 5__5 -= Time.unscaledDeltaTime; <>2__current = null; <>1__state = 1; return true; } 5__4 = null; goto IL_0165; } if (5__3 > 0f) { Scene activeScene = SceneManager.GetActiveScene(); bool num2 = string.Equals(((Scene)(ref activeScene)).name, sceneName, StringComparison.OrdinalIgnoreCase); bool flag = !5__2 || !LoadingScreenHandler.loading; if (num2 && flag) { saveManagerPlugin.lastSceneLoadSucceeded = true; return false; } 5__3 -= Time.unscaledDeltaTime; <>2__current = null; <>1__state = 2; return true; } ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("Timed out waiting for scene '" + sceneName + "' to finish loading.")); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__208 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveEnvelope envelope; public SaveManagerPlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__208(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if (envelope == null) { return false; } saveManagerPlugin.RestoreCampfires(envelope.campfires); saveManagerPlugin.RestoreContainerStates(envelope.containerStates, envelope.luggageStates); saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; case 1: <>1__state = -1; saveManagerPlugin.RestoreCampfires(envelope.campfires); saveManagerPlugin.RestoreContainerStates(envelope.containerStates, envelope.luggageStates); saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); <>2__current = (object)new WaitForSeconds(1.1f); <>1__state = 2; return true; case 2: <>1__state = -1; saveManagerPlugin.RestoreContainerStates(envelope.containerStates, envelope.luggageStates); saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); saveManagerPlugin.RestoreGroundItems(envelope.groundItems); saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__188 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float timeoutSeconds; public List players; private float 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__188(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = Mathf.Max(1f, timeoutSeconds); break; case 1: <>1__state = -1; break; } if (5__2 > 0f) { Player[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array.Length != 0) { int num = 0; for (int i = 0; i < players.Count; i++) { if (array.Any(new <>c__DisplayClass188_0 { snapshot = players[i] }.b__0)) { num++; } } if (num > 0) { return false; } } 5__2 -= Time.deltaTime; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public const string PluginGuid = "com.lucasandersen.peakallyouneedsavemanager"; public const string PluginName = "The All You Need Save Manager"; public const string PluginVersion = "1.0.0"; private const string SaveFilePattern = "*.json"; private const int UiWindowId = 129193; private const string PauseMenuButtonObjectName = "PeakSaveManagerButton"; private const float PendingSeedLifetimeSeconds = 90f; private static readonly MethodInfo RecalculateLookDirectionsMethod = AccessTools.Method(typeof(Character), "RecalculateLookDirections", (Type[])null, (Type[])null); private static readonly MethodInfo CampfireUpdateLitMethod = AccessTools.Method(typeof(Campfire), "UpdateLit", (Type[])null, (Type[])null); private static readonly MethodInfo CampfireHideLogsMethod = AccessTools.Method(typeof(Campfire), "HideLogs", (Type[])null, (Type[])null); private static readonly FieldInfo LuggageStateField = AccessTools.Field(typeof(Luggage), "state"); private static readonly MethodInfo LuggageOpenRpcMethod = AccessTools.Method(typeof(Luggage), "OpenLuggageRPC", (Type[])null, (Type[])null); private static readonly MethodInfo MenuWindowOpenMethod = AccessTools.Method(typeof(MenuWindow), "Open", (Type[])null, (Type[])null); private static readonly MethodInfo MenuWindowCloseMethod = AccessTools.Method(typeof(MenuWindow), "Close", (Type[])null, (Type[])null); private static readonly MethodInfo RespawnChestSetSpentMethod = AccessTools.PropertySetter(typeof(RespawnChest), "IsSpent"); private static readonly MethodInfo RespawnChestSetRevivedPlayersMethod = AccessTools.PropertySetter(typeof(RespawnChest), "HasRevivedPlayers"); private static readonly MethodInfo RespawnChestGetRevivedPlayersMethod = AccessTools.PropertyGetter(typeof(RespawnChest), "HasRevivedPlayers"); private static readonly FieldInfo RespawnChestRevivedPlayersField = AccessTools.Field(typeof(RespawnChest), "hasRevivedPlayers"); private static readonly MethodInfo RunManagerRpcSyncTimeMethod = AccessTools.Method(typeof(RunManager), "RPC_SyncTime", new Type[2] { typeof(float), typeof(bool) }, (Type[])null); private static readonly FieldInfo RunManagerTimerActiveField = AccessTools.Field(typeof(RunManager), "timerActive"); private static readonly PropertyInfo RopeShooterAmmoProperty = AccessTools.Property(typeof(RopeShooter), "Ammo"); private static readonly MethodInfo RopeShooterSyncRpcMethod = AccessTools.Method(typeof(RopeShooter), "Sync_Rpc", new Type[1] { typeof(bool) }, (Type[])null); private static readonly FieldInfo ItemTotalUsesField = AccessTools.Field(typeof(Item), "totalUses"); private static readonly FieldInfo ItemDataField = AccessTools.Field(typeof(Item), "data"); private static readonly FieldInfo MagicBeanVineCurrentLengthField = AccessTools.Field(typeof(MagicBeanVine), "currentLength"); private static readonly FieldInfo MagicBeanVineInitialLengthField = AccessTools.Field(typeof(MagicBeanVine), "initialLength"); private static readonly FieldInfo MagicBeanVineMaxLengthField = AccessTools.Field(typeof(MagicBeanVine), "maxLength"); private static readonly FieldInfo CloudFungusAlreadyBrokeField = AccessTools.Field(typeof(CloudFungus), "alreadyBroke"); private static readonly FieldInfo CloudFungusTimeAliveField = AccessTools.Field(typeof(CloudFungus), "timeAlive"); private static readonly FieldInfo OptionableIntHasDataField = AccessTools.Field(typeof(OptionableIntItemData), "HasData"); private static readonly FieldInfo OptionableIntValueField = AccessTools.Field(typeof(OptionableIntItemData), "Value"); private static readonly FieldInfo OptionableBoolHasDataField = AccessTools.Field(typeof(OptionableBoolItemData), "HasData"); private static readonly FieldInfo OptionableBoolValueField = AccessTools.Field(typeof(OptionableBoolItemData), "Value"); private static readonly FieldInfo CharacterDataCheckpointFlagsField = AccessTools.Field(typeof(CharacterData), "checkpointFlags"); private static readonly FieldInfo CheckpointFlagStatusesField = AccessTools.Field(typeof(CheckpointFlag), "currentStatuses"); private static readonly FieldInfo CheckpointFlagPlanterField = AccessTools.Field(typeof(CheckpointFlag), "planterCharacter"); private static readonly FieldInfo CharacterItemsCurrentSelectedSlotField = AccessTools.Field(typeof(CharacterItems), "currentSelectedSlot"); private static readonly MethodInfo CharacterItemsEquipSlotMethod = AccessTools.Method(typeof(CharacterItems), "EquipSlot", new Type[1] { typeof(Optionable) }, (Type[])null); private static readonly ConstructorInfo OptionableByteConstructor = AccessTools.Constructor(typeof(Optionable), new Type[2] { typeof(byte), typeof(byte) }, false); private static readonly FieldInfo OptionableByteHasValueField = AccessTools.Field(typeof(Optionable), "hasValue"); private static readonly FieldInfo OptionableByteValueField = AccessTools.Field(typeof(Optionable), "value"); private static readonly MethodInfo MirageLuggageSetStateMethod = AccessTools.Method(typeof(MirageLuggage), "setMirageState", new Type[1] { typeof(float) }, (Type[])null); private static readonly FieldInfo MirageLuggageRenderersField = AccessTools.Field(typeof(MirageLuggage), "renderers"); private static readonly MethodInfo DayNightTimeStringGetterMethod = AccessTools.PropertyGetter(typeof(DayNightManager), "timeString"); private static readonly MethodInfo DayNightTimeStringSetterMethod = AccessTools.PropertySetter(typeof(DayNightManager), "timeString"); private static readonly FieldInfo DayNightTimeStringField = AccessTools.Field(typeof(DayNightManager), "timeString"); private static readonly HashSet SkippedSavedStatuses = new HashSet { (STATUSTYPE)7 }; private static SaveManagerPlugin Instance; private static int? PendingSeedForLoad; private static float PendingSeedSetRealtime; private Harmony harmony; private ConfigEntry autoSaveEnabled; private ConfigEntry autoSaveIntervalSeconds; private string saveDirectory; private string preferredSaveDirectory; private string fallbackSaveDirectory; private bool showUi; private bool isLoading; private float lastAutoSaveTime; private bool lastSceneLoadSucceeded = true; private Rect windowRect = new Rect(34f, 34f, 820f, 620f); private Vector2 fileScroll = Vector2.zero; private string newSaveName = ""; private readonly List saveEntries = new List(); private string statusMessage = ""; private Color statusColor = Color.white; private float statusMessageUntil; private bool hasConfirmationPending; private string confirmationTitle = ""; private string confirmationMessage = ""; private Action confirmationAction; private bool stylesBuilt; private GUIStyle windowStyle; private GUIStyle sectionStyle; private GUIStyle titleStyle; private GUIStyle subtitleStyle; private GUIStyle normalLabelStyle; private GUIStyle errorLabelStyle; private GUIStyle softButtonStyle; private GUIStyle dangerButtonStyle; private GUIStyle textFieldStyle; private GUIStyle cardStyle; private GUIStyle cardWarningStyle; private Texture2D overlayTexture; private Texture2D windowTexture; private Texture2D sectionTexture; private Texture2D cardTexture; private Texture2D warningCardTexture; private Texture2D buttonTexture; private Texture2D buttonHoverTexture; private Texture2D dangerButtonTexture; private Texture2D textFieldTexture; private SaveManagerPausePage pauseMenuPage; private UIPageHandler pauseMenuPageHandler; private UIPage pauseMenuMainPage; private Button pauseMenuButtonTemplate; private bool quitPendingSaveDecision; private PauseMenuMainPage quitPendingPage; private bool allowVanillaQuitClick; private void Awake() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) Instance = this; autoSaveEnabled = ((BaseUnityPlugin)this).Config.Bind("AutoSave", "Enable AutoSave", true, "Automatically create rolling autosaves"); autoSaveIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind("AutoSave", "Interval Seconds", 300f, "Seconds between autosaves"); preferredSaveDirectory = Path.Combine(Paths.GameRootPath, "PeakSaves"); fallbackSaveDirectory = Path.Combine(Application.persistentDataPath, "PeakSaves"); saveDirectory = preferredSaveDirectory; EnsureSaveDirectoryReady(showStatus: false); harmony = new Harmony("com.lucasandersen.peakallyouneedsavemanager"); harmony.PatchAll(); RefreshSaveFileList(); SetStatus("Save manager ready.", Color.cyan, 2f); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded The All You Need Save Manager 1.0.0 by Lucas Andersen"); } private void OnDestroy() { try { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"Failed to unpatch Harmony cleanly: {arg}"); } DestroyUiResources(); } private void Update() { if (showUi) { Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } if (!showUi && !isLoading && autoSaveEnabled.Value && Time.time - lastAutoSaveTime > Mathf.Max(15f, autoSaveIntervalSeconds.Value)) { if (CanAutoSaveNow()) { TrySaveGame("Autosave"); } lastAutoSaveTime = Time.time; } } private bool CanAutoSaveNow() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (!CanSaveNow(showReason: false)) { return false; } Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; if (string.IsNullOrWhiteSpace(name) || !name.StartsWith("Level_", StringComparison.OrdinalIgnoreCase)) { return false; } if (LoadingScreenHandler.loading) { return false; } return true; } private void OnGUI() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (showUi) { EnsureStyles(); DrawOverlay(); GUI.depth = -1000; windowRect = GUI.Window(129193, windowRect, new WindowFunction(DrawMainWindow), "PEAK ALL YOU NEED SAVE MANAGER", windowStyle); } } private void DrawMainWindow(int _) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) float num = statusMessageUntil - Time.unscaledTime; bool flag = IsInAirportScene(); GUILayout.BeginVertical(Array.Empty()); if (!string.IsNullOrEmpty(statusMessage) && num > 0f) { Color color = GUI.color; GUI.color = statusColor; GUILayout.Label(statusMessage, sectionStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }); GUI.color = color; } if (isLoading) { GUILayout.Label("Loading save and synchronizing players...", sectionStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) }); } if (hasConfirmationPending) { DrawConfirmationPrompt(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref windowRect)).width, 24f)); return; } GUILayout.BeginVertical(sectionStyle, Array.Empty()); GUILayout.Label("Create Save", subtitleStyle, Array.Empty()); GUILayout.Space(4f); if (flag) { GUILayout.Label("You cannot save in the Airport.", errorLabelStyle, Array.Empty()); GUILayout.Space(4f); } GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Name", normalLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }); newSaveName = GUILayout.TextField(newSaveName, textFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }); GUILayout.EndHorizontal(); GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = !isLoading && !flag; if (GUILayout.Button("Quick Save", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(28f), GUILayout.Width(120f) })) { TrySaveGame("Quick Save"); } GUI.enabled = !isLoading && !flag && !string.IsNullOrWhiteSpace(newSaveName); if (GUILayout.Button("Save", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(28f), GUILayout.Width(80f) })) { string saveName = newSaveName.Trim(); newSaveName = string.Empty; TrySaveGame(saveName); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUILayout.Space(8f); GUILayout.BeginVertical(sectionStyle, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Saved Runs", subtitleStyle, Array.Empty()); GUILayout.FlexibleSpace(); GUI.enabled = !isLoading; if (GUILayout.Button("Refresh", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(90f), GUILayout.Height(24f) })) { RefreshSaveFileList(); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.Space(6f); fileScroll = GUILayout.BeginScrollView(fileScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(390f) }); if (saveEntries.Count == 0) { GUILayout.Label("No save files found.", normalLabelStyle, Array.Empty()); } else { foreach (SaveListEntry saveEntry in saveEntries) { DrawSaveCard(saveEntry); GUILayout.Space(5f); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.FlexibleSpace(); if (GUILayout.Button("Close", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(120f), GUILayout.Height(30f) })) { showUi = false; } GUILayout.EndHorizontal(); GUILayout.EndVertical(); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref windowRect)).width, 24f)); } private void DrawSaveCard(SaveListEntry entry) { GUIStyle obj = (entry.isCompatible ? cardStyle : cardWarningStyle); bool flag = CanSaveNow(showReason: false); GUILayout.BeginVertical(obj, Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(entry.fileName, titleStyle, Array.Empty()); GUILayout.FlexibleSpace(); GUILayout.Label(FormatBytes(entry.fileSize), normalLabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(78f) }); GUILayout.EndHorizontal(); if (entry.metadata != null) { string text = ((entry.metadata.savedAtUtc == default(DateTime)) ? entry.fileTime.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) : entry.metadata.savedAtUtc.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture)); int num = entry.metadata.playerCount; if (num <= 0) { num = 0; } string text2 = Safe(entry.metadata.levelName); if (entry.metadata.levelNumber.HasValue) { text2 += $" (#{entry.metadata.levelNumber.Value})"; } GUILayout.Label("Saved: " + text, normalLabelStyle, Array.Empty()); GUILayout.Label("Level: " + text2 + " Segment: " + Safe(ToDisplaySegmentName(entry.metadata.currentSegmentName, entry.metadata.biomeId)), normalLabelStyle, Array.Empty()); GUILayout.Label($"Seed: {entry.metadata.levelSeed} Ascent: {entry.metadata.ascent} Players: {num}", normalLabelStyle, Array.Empty()); GUILayout.Label(FormatRunSummary(entry.metadata), normalLabelStyle, Array.Empty()); } else { GUILayout.Label($"File Time: {entry.fileTime:yyyy-MM-dd HH:mm:ss}", normalLabelStyle, Array.Empty()); } if (!entry.isCompatible) { GUILayout.Label("Incompatible: " + entry.incompatibilityReason, errorLabelStyle, Array.Empty()); } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty()); GUI.enabled = !isLoading && entry.isCompatible; if (GUILayout.Button("Load", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(24f), GUILayout.Width(90f) })) { StartLoadFromUi(entry.fullPath); } GUI.enabled = !isLoading && flag; if (GUILayout.Button("Overwrite", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(24f), GUILayout.Width(100f) })) { string saveNameHint = ((entry.metadata != null && !string.IsNullOrWhiteSpace(entry.metadata.saveName)) ? entry.metadata.saveName : Path.GetFileNameWithoutExtension(entry.fileName)); string targetPath2 = entry.fullPath; string fileName = entry.fileName; RequestConfirmation("Overwrite Save?", "Overwrite '" + fileName + "' with your current run state?", delegate { TryOverwriteSave(targetPath2, saveNameHint); }); } GUI.enabled = !isLoading; if (GUILayout.Button("Delete", dangerButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(24f), GUILayout.Width(90f) })) { string targetPath = entry.fullPath; string fileName2 = entry.fileName; RequestConfirmation("Delete Save?", "Delete '" + fileName2 + "' permanently? This cannot be undone.", delegate { TryDeleteSave(targetPath); }); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndVertical(); } private void StartLoadFromUi(string fullPath) { if (!string.IsNullOrWhiteSpace(fullPath)) { showUi = false; ClearPendingConfirmation(); pauseMenuPage?.PrepareForLoad(); ClosePauseMenuForLoad(); ((MonoBehaviour)this).StartCoroutine(LoadSaveRoutine(fullPath)); } } private void ClosePauseMenuForLoad() { try { if ((Object)(object)EventSystem.current != (Object)null) { EventSystem.current.SetSelectedGameObject((GameObject)null); } PauseMainMenu val = Object.FindFirstObjectByType(); if ((Object)(object)val != (Object)null) { CloseMenuWindow((MenuWindow)(object)val); ((Component)val).gameObject.SetActive(false); } if ((Object)(object)pauseMenuPage != (Object)null) { ((Component)pauseMenuPage).gameObject.SetActive(false); } if ((Object)(object)pauseMenuPageHandler != (Object)null) { ((Component)pauseMenuPageHandler).gameObject.SetActive(false); } Cursor.visible = false; Cursor.lockState = (CursorLockMode)1; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to close pause menu before load: " + ex.Message)); } } private void ToggleUi() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient) { SetStatus("Only the host can open Save Manager.", Color.yellow, 2.5f); return; } showUi = !showUi; if (showUi) { RefreshSaveFileList(); Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else { ClearPendingConfirmation(); } } private void RequestConfirmation(string title, string message, Action confirmedAction) { if (confirmedAction != null) { hasConfirmationPending = true; confirmationTitle = (string.IsNullOrWhiteSpace(title) ? "Are you sure?" : title); confirmationMessage = (string.IsNullOrWhiteSpace(message) ? "Please confirm this action." : message); confirmationAction = confirmedAction; } } private void ClearPendingConfirmation() { hasConfirmationPending = false; confirmationTitle = string.Empty; confirmationMessage = string.Empty; confirmationAction = null; } private void ExecutePendingConfirmation() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) Action action = confirmationAction; ClearPendingConfirmation(); if (action == null) { return; } try { action(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Confirmation action failed: {arg}"); SetStatus("Action failed. Check BepInEx log.", Color.red, 4f); } } private void DrawConfirmationPrompt() { GUILayout.Space(8f); GUILayout.BeginVertical(sectionStyle, Array.Empty()); GUILayout.Label(confirmationTitle, subtitleStyle, Array.Empty()); GUILayout.Space(4f); GUILayout.Label(confirmationMessage, normalLabelStyle, Array.Empty()); GUILayout.Space(10f); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.FlexibleSpace(); GUI.enabled = !isLoading; if (GUILayout.Button("Cancel", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(30f), GUILayout.Width(120f) })) { ClearPendingConfirmation(); } GUI.enabled = !isLoading; if (GUILayout.Button("Confirm", dangerButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(30f), GUILayout.Width(120f) })) { ExecutePendingConfirmation(); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndVertical(); } internal static void TryAttachPauseMenuButton(PauseMenuMainPage pauseMenuPage) { Instance?.AttachPauseMenuButton(pauseMenuPage); } private void AttachPauseMenuButton(PauseMenuMainPage pauseMenuPage) { //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pauseMenuPage == (Object)null) { return; } try { object? obj = AccessTools.Field(typeof(PauseMenuMainPage), "m_settingsButton")?.GetValue(pauseMenuPage); Button val = (Button)((obj is Button) ? obj : null); if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null || (Object)(object)((Component)val).transform.parent == (Object)null) { return; } Transform parent = ((Component)val).transform.parent; Transform val2 = parent.Find("PeakSaveManagerButton"); Button component; if ((Object)(object)val2 == (Object)null) { GameObject val3 = Object.Instantiate(((Component)val).gameObject, parent, false); ((Object)val3).name = "PeakSaveManagerButton"; Transform transform = ((Component)val).transform; RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = val3.transform; RectTransform val5 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); if ((Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null) { val5.anchorMin = val4.anchorMin; val5.anchorMax = val4.anchorMax; val5.pivot = val4.pivot; val5.sizeDelta = val4.sizeDelta; ((Transform)val5).localScale = ((Transform)val4).localScale; Vector2 anchoredPosition = val4.anchoredPosition; Rect rect = val4.rect; val5.anchoredPosition = anchoredPosition + new Vector2(0f, 0f - Mathf.Max(50f, ((Rect)(ref rect)).height + 8f)); } val3.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1); MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren(true); foreach (MonoBehaviour val6 in componentsInChildren) { if ((Object)(object)val6 != (Object)null && ((object)val6).GetType().Name == "LocalizedText") { Object.Destroy((Object)(object)val6); } } SetPauseMenuButtonText(val3, "SAVE MANAGER"); component = val3.GetComponent