Decompiled source of The All You Need Save Manager v1.0.3
BepInEx\plugins\TAYNSM\TAYNSM.dll
Decompiled 16 hours ago
The result has been truncated due to the large size, download it to view full contents!
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 BepInEx.Logging; 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.1")] public sealed class SaveManagerPlugin : BaseUnityPlugin { private sealed class ProtectedGroundItemMarker { public ushort itemId; public Vector3 position; public float expiresAtRealtime; } [CompilerGenerated] private sealed class <>c__DisplayClass249_0 { public bool restored; internal void <LoadSaveRoutine>b__0(bool success) { restored = success; } } [CompilerGenerated] private sealed class <ApplyPlayerSnapshotRoutine>d__257 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PlayerSnapshot snapshot; public Action<bool> completion; public SaveManagerPlugin <>4__this; public Player player; private bool <appliedAny>5__2; private Vector3 <targetPosition>5__3; private Vector3 <targetRotation>5__4; private bool <characterApplied>5__5; private bool <inventoryApplied>5__6; private bool <selectionApplied>5__7; private Character <stabilizedCharacter>5__8; private int <pass>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ApplyPlayerSnapshotRoutine>d__257(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <stabilizedCharacter>5__8 = null; <>1__state = -2; } private bool MoveNext() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_065a: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; Player val; switch (num) { default: return false; case 0: { <>1__state = -1; <appliedAny>5__2 = false; if (snapshot == null) { completion?.Invoke(obj: false); return false; } <targetPosition>5__3 = snapshot.position.ToUnity(); <targetRotation>5__4 = snapshot.rotation.ToUnity(); int valueOrDefault = (snapshot.inventory?.mainSlots?.Count((ItemSlotSnapshot slot) => slot?.HasItem() ?? false)).GetValueOrDefault(); int valueOrDefault2 = (snapshot.inventory?.backpackSlots?.Count((ItemSlotSnapshot slot) => slot?.HasItem() ?? false)).GetValueOrDefault(); <characterApplied>5__5 = false; <inventoryApplied>5__6 = snapshot.inventory == null; <selectionApplied>5__7 = snapshot.inventory == null; <stabilizedCharacter>5__8 = null; ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)($"Begin player restore for '{snapshot.playerName}' (Actor: {snapshot.actorNumber}) " + $"items(main={valueOrDefault}, backpack={valueOrDefault2}) " + "stamina=" + (snapshot.character?.currentStamina.ToString("0.###", CultureInfo.InvariantCulture) ?? "-") + " extra=" + (snapshot.character?.extraStamina.ToString("0.###", CultureInfo.InvariantCulture) ?? "-") + ".")); <pass>5__9 = 0; goto IL_05c5; } case 1: <>1__state = -1; goto IL_027c; case 2: { <>1__state = -1; break; } IL_05c5: if (<pass>5__9 < 20) { if (<pass>5__9 > 0) { <>2__current = (object)new WaitForSeconds(0.75f); <>1__state = 1; return true; } goto IL_027c; } goto IL_05d2; IL_027c: val = saveManagerPlugin.ResolveRestoreTargetPlayer(snapshot, player); if (!IsUsablePlayerForRestore(val)) { saveManagerPlugin.LogVerbose($"Player restore pass {<pass>5__9 + 1}: target player not usable yet for '{snapshot.playerName}'."); } else { Character character = val.character; if ((Object)(object)character == (Object)null) { saveManagerPlugin.LogVerbose($"Player restore pass {<pass>5__9 + 1}: character missing for '{snapshot.playerName}'."); } else { saveManagerPlugin.LogVerbose($"Player restore pass {<pass>5__9 + 1}: target='{Safe(((Object)val).name)}' " + "character='" + Safe(((Object)character).name) + "'"); bool flag = false; if (!<characterApplied>5__5) { try { if (snapshot.character != null) { saveManagerPlugin.ApplyCharacterSnapshot(character, snapshot.character); } TryWarpCharacterViaRpc(character, <targetPosition>5__3); ApplyCharacterTransformSnapshot(character, <targetPosition>5__3, <targetRotation>5__4); PhotonView photonView = GetPhotonView((Component)(object)character); if ((Object)(object)character.data != (Object)null && snapshot.character != null && ((Object)(object)photonView == (Object)null || photonView.IsMine)) { character.data.lookValues = snapshot.character.lookValues.ToUnity(); RecalculateLookDirectionsMethod?.Invoke(character, null); } ApplyCharacterVelocity(character, snapshot.velocity, snapshot.angularVelocity); <characterApplied>5__5 = true; <stabilizedCharacter>5__8 = character; flag = true; } catch (Exception arg) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)$"Player character restore pass {<pass>5__9 + 1} failed for '{snapshot.playerName}': {arg}"); } } if (snapshot.inventory != null) { if (!<inventoryApplied>5__6) { try { saveManagerPlugin.ApplyInventory(val, character, snapshot.inventory); <inventoryApplied>5__6 = true; flag = true; } catch (Exception arg2) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)$"Player inventory restore pass {<pass>5__9 + 1} failed for '{snapshot.playerName}': {arg2}"); } } if (<inventoryApplied>5__6 && !<selectionApplied>5__7) { try { ApplyEquippedSelection(val, character, snapshot.inventory); <selectionApplied>5__7 = true; flag = true; } catch (Exception arg3) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)$"Player equipped-item restore pass {<pass>5__9 + 1} failed for '{snapshot.playerName}': {arg3}"); } } } if (flag) { <appliedAny>5__2 = true; ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Applied player snapshot pass {<pass>5__9 + 1}/{20} for '{snapshot.playerName}'."); } if (<characterApplied>5__5 & <inventoryApplied>5__6 & <selectionApplied>5__7) { <appliedAny>5__2 = true; saveManagerPlugin.LogVerbose($"Player restore completed all required sections on pass {<pass>5__9 + 1}. Ending retry loop early."); goto IL_05d2; } } } <pass>5__9++; goto IL_05c5; IL_05d2: if (!<appliedAny>5__2) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)$"No player snapshot passes succeeded for '{snapshot.playerName}' (Actor: {snapshot.actorNumber})."); } else { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Finished player restore for '{snapshot.playerName}' with {20} pass(es)."); } if ((<appliedAny>5__2 & <characterApplied>5__5) && (Object)(object)<stabilizedCharacter>5__8 != (Object)null) { <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.StabilizeCharacterAfterLoad(<stabilizedCharacter>5__8, <targetPosition>5__3, <targetRotation>5__4)); <>1__state = 2; return true; } break; } completion?.Invoke(<appliedAny>5__2); 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 <DelayedOverflowTempEquipRoutine>d__281 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public int playerKey; public int generation; public Player player; public ushort expectedItemId; public Character character; private int <attempt>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedOverflowTempEquipRoutine>d__281(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(0.2f); <>1__state = 1; return true; case 1: <>1__state = -1; <attempt>5__2 = 0; goto IL_0334; case 2: { <>1__state = -1; goto IL_009e; } IL_0334: if (<attempt>5__2 < 24) { if (!saveManagerPlugin.overflowTempEquipGenerationByPlayer.TryGetValue(playerKey, out var value) || value != generation) { return false; } if (<attempt>5__2 > 0) { <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 2; return true; } goto IL_009e; } saveManagerPlugin.LogVerbose($"Delayed overflow temp equip failed after {24} attempts for item {expectedItemId}."); saveManagerPlugin.ClearOverflowTempEquipGenerationIfCurrent(playerKey, generation); return false; IL_009e: if (IsUsablePlayerForRestore(player) && player.tempFullSlot != null && !((Object)(object)player.tempFullSlot.prefab == (Object)null) && player.tempFullSlot.prefab.itemID == expectedItemId) { Character val = character; if ((Object)(object)val == (Object)null) { val = player.character; } CharacterItems val2 = (((Object)(object)val != (Object)null && val.refs != null) ? val.refs.items : null); if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val == (Object)null)) { if (IsCharacterHoldingItem(val, expectedItemId)) { saveManagerPlugin.TrySyncInventoryNetwork(player); saveManagerPlugin.LogVerbose($"Delayed overflow temp equip confirmed already held on attempt {<attempt>5__2 + 1}/{24} for item {expectedItemId}."); saveManagerPlugin.ClearOverflowTempEquipGenerationIfCurrent(playerKey, generation); return false; } bool flag = TryEquipItem(val2, player.tempFullSlot.prefab); bool flag2 = IsCharacterHoldingItem(val, expectedItemId); bool flag3 = false; bool flag4 = false; if (!flag2) { flag3 = TryEquipSlot(val2, 250); flag4 = IsCharacterSelectedSlot(val, 250); flag2 = IsCharacterHoldingItem(val, expectedItemId); } if (flag2 || flag4) { saveManagerPlugin.TrySyncInventoryNetwork(player); saveManagerPlugin.LogVerbose($"Delayed overflow temp equip succeeded on attempt {<attempt>5__2 + 1}/{24}. " + $"TempItem={expectedItemId} InvokeItem={flag} " + $"InvokeOverflowSlot={flag3} Holding={flag2} " + $"SelectedOverflow={flag4}"); saveManagerPlugin.ClearOverflowTempEquipGenerationIfCurrent(playerKey, generation); return false; } if (<attempt>5__2 == 0 || <attempt>5__2 == 23 || (<attempt>5__2 + 1) % 6 == 0) { saveManagerPlugin.LogVerbose($"Delayed overflow temp equip retry {<attempt>5__2 + 1}/{24}. TempItem={expectedItemId} " + $"InvokeItem={flag} InvokeOverflowSlot={flag3} " + $"Holding={flag2} SelectedOverflow={flag4}"); } } } <attempt>5__2++; goto IL_0334; } } 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 <EnsurePendingSeedAppliedRoutine>d__251 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public string sceneName; private int <seed>5__2; private float <timeout>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnsurePendingSeedAppliedRoutine>d__251(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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; if (!PendingSeedForLoad.HasValue || PendingSeedConsumedForLoad) { return false; } <seed>5__2 = PendingSeedForLoad.Value; <timeout>5__3 = 4f; break; case 1: <>1__state = -1; break; } if (<timeout>5__3 > 0f && !PendingSeedConsumedForLoad) { if (saveManagerPlugin.TryForceApplyPendingSeedToGeneration(<seed>5__2, sceneName)) { return false; } <timeout>5__3 -= Time.unscaledDeltaTime; <>2__current = null; <>1__state = 1; return true; } if (!PendingSeedConsumedForLoad) { ManualLogSource logger = ((BaseUnityPlugin)saveManagerPlugin).Logger; string[] obj = new string[6] { $"Pending seed {<seed>5__2} could not be force-applied before restore. ", "Scene='", Safe(sceneName), "' ActiveScene='", null, null }; Scene activeScene = SceneManager.GetActiveScene(); obj[4] = ((Scene)(ref activeScene)).name; obj[5] = "'."; logger.LogWarning((object)string.Concat(obj)); } 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 <EnumeratePlayersFromHandler>d__216 : IEnumerable<Player>, IEnumerable, IEnumerator<Player>, IDisposable, IEnumerator { private int <>1__state; private Player <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; Player IEnumerator<Player>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnumeratePlayersFromHandler>d__216(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<Player> IEnumerable<Player>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <EnumeratePlayersFromHandler>d__216(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Player>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <LoadSaveRoutine>d__249 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public string fullPath; private <>c__DisplayClass249_0 <>8__1; private SaveEnvelope <envelope>5__2; private string <targetScene>5__3; private bool <needsSceneLoad>5__4; private int <appliedCount>5__5; private Player <forcedSinglePlayerTarget>5__6; private Segment <targetSegment>5__7; private List<PlayerSnapshot>.Enumerator <>7__wrap7; private PlayerSnapshot <playerSnapshot>5__9; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadSaveRoutine>d__249(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 6u) { try { if (num == -4 || num == 7) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>8__1 = null; <envelope>5__2 = null; <targetScene>5__3 = null; <forcedSinglePlayerTarget>5__6 = null; <>7__wrap7 = default(List<PlayerSnapshot>.Enumerator); <playerSnapshot>5__9 = null; <>1__state = -2; } private bool MoveNext() { //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0718: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_0654: Unknown result type (might be due to invalid IL or missing references) //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_068a: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_06a5: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_06aa: Unknown result type (might be due to invalid IL or missing references) //IL_06b2: Unknown result type (might be due to invalid IL or missing references) //IL_06ba: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Unknown result type (might be due to invalid IL or missing references) //IL_06dc: Unknown result type (might be due to invalid IL or missing references) //IL_0a0f: Unknown result type (might be due to invalid IL or missing references) //IL_09bd: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Unknown result type (might be due to invalid IL or missing references) //IL_06fb: Expected O, but got Unknown //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) bool result; try { int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; Scene activeScene; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; if (saveManagerPlugin.isLoading) { result = false; } else { saveManagerPlugin.isLoading = true; saveManagerPlugin.loadStartedRealtime = Time.realtimeSinceStartup; saveManagerPlugin.SetStatus("Loading save...", Color.cyan, 10f); <>1__state = -3; saveManagerPlugin.overflowTempEquipGenerationByPlayer.Clear(); saveManagerPlugin.protectedGroundItemMarkers.Clear(); saveManagerPlugin.ropeLinkRestoreSettledForCurrentLoad = false; saveManagerPlugin.lastRopeLinkRestoreRealtime = -1f; saveManagerPlugin.lastRopeLinkExpectedCount = -1; saveManagerPlugin.lastRopeLinkResolvedCount = -1; saveManagerPlugin.lastGroundRestorePhase = string.Empty; saveManagerPlugin.lastGroundRestoreMatchedAllForCurrentPhase = false; saveManagerPlugin.lastGroundRestoreHadFailuresForCurrentPhase = false; saveManagerPlugin.lateWorldReconcileToken++; if (saveManagerPlugin.lateWorldReconcileCoroutine != null) { ((MonoBehaviour)saveManagerPlugin).StopCoroutine(saveManagerPlugin.lateWorldReconcileCoroutine); saveManagerPlugin.lateWorldReconcileCoroutine = null; } if (saveManagerPlugin.deferredGroundRestoreCoroutine != null) { ((MonoBehaviour)saveManagerPlugin).StopCoroutine(saveManagerPlugin.deferredGroundRestoreCoroutine); saveManagerPlugin.deferredGroundRestoreCoroutine = null; } string[] obj = new string[6] { "LoadSaveRoutine start. Path='", Safe(fullPath), "' ActiveScene='", null, null, null }; activeScene = SceneManager.GetActiveScene(); obj[3] = ((Scene)(ref activeScene)).name; obj[4] = "' "; obj[5] = $"InRoom={PhotonNetwork.InRoom} IsHost={PhotonNetwork.IsMasterClient}"; saveManagerPlugin.LogVerbose(string.Concat(obj)); if (!TryReadSaveEnvelope(fullPath, out <envelope>5__2, out var reason)) { saveManagerPlugin.SetStatus("Incompatible save: " + reason, Color.yellow, 6f); saveManagerPlugin.LogVerbose("Load rejected by TryReadSaveEnvelope. Reason='" + Safe(reason) + "'"); result = false; break; } saveManagerPlugin.LogVerbose("Loaded envelope from disk. " + DescribeEnvelope(<envelope>5__2)); if (<envelope>5__2.players != null) { for (int i = 0; i < <envelope>5__2.players.Count; i++) { saveManagerPlugin.LogVerbose("Envelope player: " + DescribePlayerSnapshot(<envelope>5__2.players[i])); } } if (<envelope>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; } saveManagerPlugin.ApplySavedDailyLevelIndexOverride(<envelope>5__2.metadata); <targetScene>5__3 = ResolveTargetScene(<envelope>5__2.metadata); bool flag = SaveNeedsNonAirportScene(<envelope>5__2.metadata); string text = $"Load scene resolve. TargetScene='{Safe(<targetScene>5__3)}' SaveNeedsRunScene={flag} "; activeScene = SceneManager.GetActiveScene(); saveManagerPlugin.LogVerbose(text + "CurrentScene='" + ((Scene)(ref activeScene)).name + "'"); if (string.IsNullOrWhiteSpace(<targetScene>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(<targetScene>5__3)) { activeScene = SceneManager.GetActiveScene(); num2 = ((!string.Equals(((Scene)(ref activeScene)).name, <targetScene>5__3, StringComparison.OrdinalIgnoreCase)) ? 1 : 0); } else { num2 = 0; } <needsSceneLoad>5__4 = (byte)num2 != 0; saveManagerPlugin.LogVerbose($"Load scene decision. NeedsSceneLoad={<needsSceneLoad>5__4}"); if (<envelope>5__2.metadata.levelSeed != 0) { SetPendingSeedForLoad(<envelope>5__2.metadata.levelSeed); ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Queued seed {PendingSeedForLoad.Value} for next level generation"); } else { ClearPendingSeedForLoad(); } if (!<needsSceneLoad>5__4) { Ascents.currentAscent = <envelope>5__2.metadata.ascent; saveManagerPlugin.LogVerbose($"Scene load skipped. Applied ascent={<envelope>5__2.metadata.ascent} on current scene."); goto IL_04ff; } saveManagerPlugin.LogVerbose($"Starting scene load to '{<targetScene>5__3}' with ascent={<envelope>5__2.metadata.ascent}."); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.LoadSceneRoutine(<targetScene>5__3, <envelope>5__2.metadata.ascent)); <>1__state = 1; result = true; } goto end_IL_0000; case 1: { <>1__state = -3; object arg = saveManagerPlugin.lastSceneLoadSucceeded; activeScene = SceneManager.GetActiveScene(); saveManagerPlugin.LogVerbose($"Scene load routine returned. Success={arg} ActiveScene='{((Scene)(ref activeScene)).name}'"); if (!saveManagerPlugin.lastSceneLoadSucceeded) { saveManagerPlugin.SetStatus("Failed to load scene '" + <targetScene>5__3 + "'.", Color.red, 6f); result = false; break; } goto IL_04ff; } case 2: <>1__state = -3; goto IL_0571; case 3: <>1__state = -3; goto IL_05ad; case 4: { <>1__state = -3; int num3 = saveManagerPlugin.CountMatchedPlayers(<envelope>5__2.players); saveManagerPlugin.LogVerbose($"Player wait completed. MatchedPlayers={num3}/{<envelope>5__2.players.Count}"); if (num3 <= 0) { saveManagerPlugin.SetStatus("No matching players were found for this save.", Color.yellow, 6f); result = false; break; } if (!MapHandler.Exists) { goto IL_072c; } <targetSegment>5__7 = ClampSegment(<envelope>5__2.metadata.currentSegment); MapHandler val2 = Object.FindFirstObjectByType<MapHandler>(); Segment val3 = (Segment)(((Object)(object)val2 != (Object)null) ? ((int)val2.GetCurrentSegment()) : 0); saveManagerPlugin.LogVerbose($"Map segment before load restore. Current={val3} Target={<targetSegment>5__7}"); if ((int)<targetSegment>5__7 == 0 || <targetSegment>5__7 == val3) { goto IL_072c; } MapHandler.JumpToSegment(<targetSegment>5__7); <>2__current = (object)new WaitForSeconds(0.75f); <>1__state = 5; result = true; goto end_IL_0000; } case 5: <>1__state = -3; saveManagerPlugin.LogVerbose($"Map segment jump applied to {<targetSegment>5__7}."); goto IL_072c; case 6: <>1__state = -3; saveManagerPlugin.LogVerbose("Completed immediate world-interactable restore."); <appliedCount>5__5 = 0; ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Applying {<envelope>5__2.players.Count} player snapshot(s) from '{Path.GetFileName(fullPath)}'."); <forcedSinglePlayerTarget>5__6 = ((<envelope>5__2.players.Count == 1) ? FindPrimaryLocalPlayer() : null); if ((Object)(object)<forcedSinglePlayerTarget>5__6 != (Object)null) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)"Single-player load detected: forcing restore target to the current local player."); } <>7__wrap7 = <envelope>5__2.players.GetEnumerator(); <>1__state = -4; goto IL_098c; case 7: { <>1__state = -4; if (<>8__1.restored) { <appliedCount>5__5++; } else { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)$"Player snapshot restore failed for '{<playerSnapshot>5__9.playerName}' (Actor: {<playerSnapshot>5__9.actorNumber})."); } <>8__1 = null; <playerSnapshot>5__9 = null; goto IL_098c; } IL_04ff: if (!<needsSceneLoad>5__4 || !PendingSeedForLoad.HasValue || PendingSeedConsumedForLoad) { goto IL_0571; } saveManagerPlugin.LogVerbose($"Pending seed {PendingSeedForLoad.Value} was not consumed during scene load; " + "attempting direct generator seed apply."); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.EnsurePendingSeedAppliedRoutine(<targetScene>5__3)); <>1__state = 2; result = true; goto end_IL_0000; IL_05ad: saveManagerPlugin.LogVerbose($"Waiting for players. SnapshotPlayers={<envelope>5__2.players.Count}"); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.WaitForPlayersRoutine(<envelope>5__2.players, 20f)); <>1__state = 4; result = true; goto end_IL_0000; IL_072c: saveManagerPlugin.LogVerbose("Starting world-interactable restore."); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreWorldInteractablesRoutine(<envelope>5__2)); <>1__state = 6; result = true; goto end_IL_0000; IL_0571: if (!<needsSceneLoad>5__4) { goto IL_05ad; } <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.WaitForLoadedSceneWorldReadyRoutine(<targetScene>5__3, <envelope>5__2)); <>1__state = 3; result = true; goto end_IL_0000; IL_098c: while (true) { if (<>7__wrap7.MoveNext()) { <playerSnapshot>5__9 = <>7__wrap7.Current; <>8__1 = new <>c__DisplayClass249_0(); Player val = <forcedSinglePlayerTarget>5__6 ?? saveManagerPlugin.FindPlayer(<playerSnapshot>5__9); string arg2 = (((Object)(object)val != (Object)null) ? Safe(((Object)val).name) : "-"); saveManagerPlugin.LogVerbose($"Player restore target resolve. Snapshot='{Safe(<playerSnapshot>5__9?.playerName)}' Actor={<playerSnapshot>5__9?.actorNumber ?? (-1)} Target='{arg2}'"); if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)$"Could not find player for snapshot '{<playerSnapshot>5__9.playerName}' (Actor: {<playerSnapshot>5__9.actorNumber})"); continue; } <>8__1.restored = false; <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.ApplyPlayerSnapshotRoutine(val, <playerSnapshot>5__9, delegate(bool success) { <>8__1.restored = success; })); <>1__state = 7; result = true; } else { <>m__Finally2(); <>7__wrap7 = default(List<PlayerSnapshot>.Enumerator); if (<appliedCount>5__5 <= 0) { saveManagerPlugin.SetStatus("Load finished but no players were restored.", Color.yellow, 6f); result = false; break; } saveManagerPlugin.RestoreRunMetadata(<envelope>5__2.metadata); saveManagerPlugin.SetStatus($"Loaded save successfully ({<appliedCount>5__5}/{<envelope>5__2.players.Count} players).", Color.green, 4f); saveManagerPlugin.LogVerbose($"Load completed. AppliedPlayers={<appliedCount>5__5}/{<envelope>5__2.players.Count}"); <envelope>5__2 = null; <targetScene>5__3 = null; <forcedSinglePlayerTarget>5__6 = null; <>m__Finally1(); result = false; } goto end_IL_0000; } break; } <>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; ClearForcedDailyLevelIndexForLoad(); ClearPendingSeedForLoad(); saveManagerPlugin.isLoading = false; saveManagerPlugin.loadStartedRealtime = -1f; saveManagerPlugin.RefreshSaveFileList(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap7).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadSceneRoutine>d__250 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveManagerPlugin <>4__this; public int ascent; public string sceneName; private bool <usedLoadingScreen>5__2; private float <timeout>5__3; private float <nextProgressLogAt>5__4; private bool <triedEmergencySceneFallback>5__5; private AsyncOperation <operation>5__6; private float <fallbackTimeout>5__7; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadSceneRoutine>d__250(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <operation>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: 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; saveManagerPlugin.LogVerbose($"LoadSceneRoutine start. Scene='{sceneName}' Ascent={ascent}"); try { GameHandler.AddStatus<SceneSwitchingStatus>((GameStatus)new SceneSwitchingStatus()); } catch (Exception ex) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("Could not set scene switching status: " + ex.Message)); } <usedLoadingScreen>5__2 = false; bool flag = saveManagerPlugin.TryBeginIslandLoadFromAirport(sceneName, ascent); if (flag) { <usedLoadingScreen>5__2 = true; saveManagerPlugin.LogVerbose("LoadSceneRoutine started via AirportCheckInKiosk.BeginIslandLoadRPC."); } else { try { LoadingScreenHandler instance = RetrievableResourceSingleton<LoadingScreenHandler>.Instance; if ((Object)(object)instance != (Object)null) { instance.Load((LoadingScreenType)1, (Action)null, new IEnumerator[1] { instance.LoadSceneProcess(sceneName, true, true, 0.5f) }); <usedLoadingScreen>5__2 = true; saveManagerPlugin.LogVerbose("LoadSceneRoutine using LoadingScreenHandler process."); } } catch (Exception ex2) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("LoadingScreenHandler load failed, using fallback load: " + ex2.Message)); } } if (!<usedLoadingScreen>5__2 && !flag) { saveManagerPlugin.LogVerbose("LoadSceneRoutine falling back to SceneManager.LoadSceneAsync."); <operation>5__6 = SceneManager.LoadSceneAsync(sceneName); if (<operation>5__6 == null) { ((BaseUnityPlugin)saveManagerPlugin).Logger.LogError((object)("Could not start fallback scene load for '" + sceneName + "'.")); return false; } <fallbackTimeout>5__7 = 45f; goto IL_01b0; } goto IL_01fc; } case 1: <>1__state = -1; goto IL_01b0; case 2: { <>1__state = -1; break; } IL_01b0: if (!<operation>5__6.isDone && <fallbackTimeout>5__7 > 0f) { <fallbackTimeout>5__7 -= Time.unscaledDeltaTime; <>2__current = null; <>1__state = 1; return true; } saveManagerPlugin.LogVerbose($"Fallback scene load loop finished. Done={<operation>5__6.isDone} RemainingTimeout={<fallbackTimeout>5__7:0.##}s"); <operation>5__6 = null; goto IL_01fc; IL_01fc: <timeout>5__3 = 45f; <nextProgressLogAt>5__4 = <timeout>5__3; <triedEmergencySceneFallback>5__5 = false; break; } Scene activeScene; if (<timeout>5__3 > 0f) { activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; bool flag2 = string.Equals(name, sceneName, StringComparison.OrdinalIgnoreCase); bool flag3 = !<usedLoadingScreen>5__2 || !LoadingScreenHandler.loading; if (flag2 && flag3) { saveManagerPlugin.lastSceneLoadSucceeded = true; saveManagerPlugin.LogVerbose("LoadSceneRoutine success. ActiveScene='" + name + "'"); return false; } if ((!<triedEmergencySceneFallback>5__5 & <usedLoadingScreen>5__2) && string.Equals(name, "Airport", StringComparison.OrdinalIgnoreCase) && <timeout>5__3 < 35f) { <triedEmergencySceneFallback>5__5 = true; if (SceneManager.LoadSceneAsync(sceneName) != null) { <usedLoadingScreen>5__2 = false; saveManagerPlugin.LogVerbose("LoadSceneRoutine emergency fallback started SceneManager.LoadSceneAsync."); } else { saveManagerPlugin.LogVerbose("LoadSceneRoutine emergency fallback could not start SceneManager.LoadSceneAsync."); } } if (saveManagerPlugin.IsVerboseLoggingEnabled() && <timeout>5__3 <= <nextProgressLogAt>5__4 - 1f) { <nextProgressLogAt>5__4 = <timeout>5__3; saveManagerPlugin.LogVerbose($"LoadSceneRoutine progress. Remaining={<timeout>5__3:0.##}s ActiveScene='{name}' " + $"SceneMatches={flag2} LoadingScreenBusy={<usedLoadingScreen>5__2 && LoadingScreenHandler.loading}"); } <timeout>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.")); TryForceClearLoadingScreenBusyFlag(); activeScene = SceneManager.GetActiveScene(); saveManagerPlugin.LogVerbose("LoadSceneRoutine timeout. ActiveScene='" + ((Scene)(ref activeScene)).name + "'"); 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 <RestoreGroundItemsDeferredRoutine>d__307 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public List<GroundItemSnapshot> snapshots; public string label; public SaveManagerPlugin <>4__this; private string <phase>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestoreGroundItemsDeferredRoutine>d__307(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <phase>5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: result = false; break; case 0: <>1__state = -1; <>1__state = -3; if (snapshots == null || snapshots.Count == 0) { result = false; <>m__Finally1(); break; } <phase>5__2 = (string.IsNullOrWhiteSpace(label) ? "deferred" : label.Trim()); <>2__current = null; <>1__state = 1; result = true; break; case 1: <>1__state = -3; saveManagerPlugin.LogVerbose($"Deferred ground restore '{<phase>5__2}' starting. SnapshotCount={snapshots.Count}"); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreGroundItemsRoutine(snapshots, <phase>5__2)); <>1__state = 2; result = true; break; case 2: <>1__state = -3; <phase>5__2 = null; <>m__Finally1(); result = false; break; } } 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; <>4__this.deferredGroundRestoreCoroutine = null; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RestoreGroundItemsRoutine>d__320 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public List<GroundItemSnapshot> itemSnapshots; public string phaseLabel; public SaveManagerPlugin <>4__this; private string <phase>5__2; private bool <allowExtraCleanup>5__3; private bool <allowSpawning>5__4; private List<Item> <candidates>5__5; private int <matchedCount>5__6; private int <spawnedCount>5__7; private int <failedSpawnCount>5__8; private int <removedCount>5__9; private int <preservedCount>5__10; private int <errorCount>5__11; private int <i>5__12; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestoreGroundItemsRoutine>d__320(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <phase>5__2 = null; <candidates>5__5 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; Item val3; switch (num) { default: return false; case 0: { <>1__state = -1; if (itemSnapshots == null) { return false; } <phase>5__2 = (string.IsNullOrWhiteSpace(phaseLabel) ? "ground" : phaseLabel.Trim()); <allowExtraCleanup>5__3 = !<phase>5__2.StartsWith("late-", StringComparison.OrdinalIgnoreCase); <allowSpawning>5__4 = <phase>5__2.StartsWith("late-", StringComparison.OrdinalIgnoreCase); Item[] source = Object.FindObjectsByType<Item>((FindObjectsSortMode)0); <candidates>5__5 = new List<Item>(source.Where(IsGroundItemCandidate)); int count = <candidates>5__5.Count; <matchedCount>5__6 = 0; <spawnedCount>5__7 = 0; <failedSpawnCount>5__8 = 0; <removedCount>5__9 = 0; <preservedCount>5__10 = 0; <errorCount>5__11 = 0; saveManagerPlugin.PruneExpiredProtectedGroundMarkers(); saveManagerPlugin.LogVerbose($"RestoreGroundItems[{<phase>5__2}] start. Snapshots={itemSnapshots.Count} CandidateGroundItems={count}"); <i>5__12 = 0; goto IL_02f5; } case 1: <>1__state = -1; goto IL_02e3; case 2: { <>1__state = -1; goto IL_047f; } IL_02f5: if (<i>5__12 < itemSnapshots.Count) { try { GroundItemSnapshot groundItemSnapshot = itemSnapshots[<i>5__12]; if (groundItemSnapshot != null && groundItemSnapshot.itemId != ushort.MaxValue) { Item val = FindGroundItemForSnapshot(groundItemSnapshot, <candidates>5__5, 16f); if ((Object)(object)val != (Object)null) { <candidates>5__5.Remove(val); ApplyGroundItemSnapshot(val, groundItemSnapshot); <matchedCount>5__6++; } else if (<allowSpawning>5__4) { Item val2 = saveManagerPlugin.TrySpawnGroundItem(groundItemSnapshot); if ((Object)(object)val2 != (Object)null) { ApplyGroundItemSnapshot(val2, groundItemSnapshot); <spawnedCount>5__7++; } else { <failedSpawnCount>5__8++; } goto IL_023c; } } } catch (Exception ex) { <errorCount>5__11++; ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)$"RestoreGroundItems[{<phase>5__2}] failed at snapshot index {<i>5__12}: {ex.Message}"); goto IL_023c; } goto IL_02e3; } if (<allowExtraCleanup>5__3) { <i>5__12 = 0; goto IL_0491; } saveManagerPlugin.LogVerbose($"RestoreGroundItems[{<phase>5__2}] skipped extra cleanup pass; preserving {<candidates>5__5.Count} unmatched candidates."); break; IL_02e3: <i>5__12++; goto IL_02f5; IL_0491: if (<i>5__12 >= <candidates>5__5.Count) { break; } val3 = <candidates>5__5[<i>5__12]; if (!((Object)(object)val3 == (Object)null)) { if (saveManagerPlugin.ShouldPreserveGroundItemDuringCleanup(val3)) { <preservedCount>5__10++; } else { try { if (!PhotonNetwork.InRoom) { goto IL_03ab; } PhotonView photonView = GetPhotonView((Component)(object)val3); if (!((Object)(object)photonView != (Object)null) || photonView.ViewID <= 0) { goto IL_03ab; } PhotonNetwork.Destroy(((Component)val3).gameObject); <removedCount>5__9++; goto end_IL_0364; IL_03ab: Object.Destroy((Object)(object)((Component)val3).gameObject); <removedCount>5__9++; goto IL_03fd; end_IL_0364:; } catch (Exception ex2) { <errorCount>5__11++; ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("Failed to remove extra ground item: " + ex2.Message)); goto IL_03fd; } } } goto IL_047f; IL_03fd: if ((<i>5__12 + 1) % 20 == 0) { saveManagerPlugin.LogVerbose($"RestoreGroundItems[{<phase>5__2}] cleanup progress {<i>5__12 + 1}/{<candidates>5__5.Count} removed={<removedCount>5__9} errors={<errorCount>5__11}"); <>2__current = null; <>1__state = 2; return true; } goto IL_047f; IL_047f: <i>5__12++; goto IL_0491; IL_023c: if ((<i>5__12 + 1) % 20 == 0) { saveManagerPlugin.LogVerbose($"RestoreGroundItems[{<phase>5__2}] progress {<i>5__12 + 1}/{itemSnapshots.Count} " + $"matched={<matchedCount>5__6} spawned={<spawnedCount>5__7} spawnFailed={<failedSpawnCount>5__8} errors={<errorCount>5__11}"); <>2__current = null; <>1__state = 1; return true; } goto IL_02e3; } saveManagerPlugin.LogVerbose($"RestoreGroundItems[{<phase>5__2}] finished. Matched={<matchedCount>5__6} Spawned={<spawnedCount>5__7} " + $"SpawnFailed={<failedSpawnCount>5__8} RemovedExtras={<removedCount>5__9} PreservedExtras={<preservedCount>5__10} " + $"Errors={<errorCount>5__11} UnmatchedCandidates={<candidates>5__5.Count}"); int num2 = <matchedCount>5__6 + <spawnedCount>5__7; saveManagerPlugin.lastGroundRestorePhase = <phase>5__2; saveManagerPlugin.lastGroundRestoreMatchedAllForCurrentPhase = num2 >= itemSnapshots.Count; saveManagerPlugin.lastGroundRestoreHadFailuresForCurrentPhase = <failedSpawnCount>5__8 > 0 || <errorCount>5__11 > 0; 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 <RestoreWorldInteractablesRoutine>d__305 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveEnvelope envelope; public SaveManagerPlugin <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestoreWorldInteractablesRoutine>d__305(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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.LogVerbose($"RestoreWorldInteractables start. Campfires={envelope.campfires?.Count ?? 0} " + $"Containers={envelope.containerStates?.Count ?? 0} GroundItems={envelope.groundItems?.Count ?? 0} " + $"WorldObjects={envelope.worldObjects?.Count ?? 0}"); saveManagerPlugin.RestoreCampfires(envelope.campfires); saveManagerPlugin.RestoreContainerStates(envelope.containerStates, envelope.luggageStates); saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); saveManagerPlugin.LogVerbose("RestoreWorldInteractables pass 1 complete."); <>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); saveManagerPlugin.LogVerbose("RestoreWorldInteractables pass 2 complete."); <>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.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); saveManagerPlugin.LogVerbose("RestoreWorldInteractables pass 3 complete."); if ((Object)(object)saveManagerPlugin != (Object)null && (Object)(object)((Component)saveManagerPlugin).gameObject != (Object)null && ((Component)saveManagerPlugin).gameObject.activeInHierarchy) { if (saveManagerPlugin.deferredGroundRestoreCoroutine != null) { ((MonoBehaviour)saveManagerPlugin).StopCoroutine(saveManagerPlugin.deferredGroundRestoreCoroutine); } saveManagerPlugin.deferredGroundRestoreCoroutine = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreGroundItemsDeferredRoutine(envelope.groundItems, "main")); } if ((Object)(object)saveManagerPlugin != (Object)null && (Object)(object)((Component)saveManagerPlugin).gameObject != (Object)null && ((Component)saveManagerPlugin).gameObject.activeInHierarchy) { if (saveManagerPlugin.lateWorldReconcileCoroutine != null) { ((MonoBehaviour)saveManagerPlugin).StopCoroutine(saveManagerPlugin.lateWorldReconcileCoroutine); } int reconcileToken = ++saveManagerPlugin.lateWorldReconcileToken; saveManagerPlugin.lateWorldReconcileCoroutine = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreWorldLatePassesRoutine(envelope, reconcileToken)); saveManagerPlugin.LogVerbose("RestoreWorldInteractables queued late passes."); } 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 <RestoreWorldLatePassesRoutine>d__306 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SaveEnvelope envelope; public int reconcileToken; public SaveManagerPlugin <>4__this; private float[] <latePassDelays>5__2; private bool <groundSettled>5__3; private int <i>5__4; private bool <runGroundReconcile>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RestoreWorldLatePassesRoutine>d__306(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } <latePassDelays>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown bool result; try { int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; bool flag; bool num2; bool ropeLinkRestoreSettledForCurrentLoad; switch (num) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; if (envelope != null && reconcileToken == saveManagerPlugin.lateWorldReconcileToken) { <latePassDelays>5__2 = new float[3] { 2.6f, 2f, 2f }; <>1__state = -3; <groundSettled>5__3 = false; <i>5__4 = 0; goto IL_02f5; } result = false; goto end_IL_0000; case 1: <>1__state = -3; if (reconcileToken != saveManagerPlugin.lateWorldReconcileToken) { result = false; break; } saveManagerPlugin.LogVerbose($"Starting late world reconcile pass {<i>5__4 + 1}/{<latePassDelays>5__2.Length} after delay={<latePassDelays>5__2[<i>5__4]:0.##}s."); <runGroundReconcile>5__5 = <i>5__4 == 0 || !<groundSettled>5__3; if (!<runGroundReconcile>5__5) { goto IL_01aa; } saveManagerPlugin.RestoreCampfires(envelope.campfires); saveManagerPlugin.RestoreContainerStates(envelope.containerStates, envelope.luggageStates); <>2__current = ((MonoBehaviour)saveManagerPlugin).StartCoroutine(saveManagerPlugin.RestoreGroundItemsRoutine(envelope.groundItems, $"late-{<i>5__4 + 1}")); <>1__state = 2; result = true; goto end_IL_0000; case 2: { <>1__state = -3; goto IL_01aa; } IL_02f5: if (<i>5__4 >= <latePassDelays>5__2.Length) { goto IL_0308; } if (reconcileToken != saveManagerPlugin.lateWorldReconcileToken) { result = false; break; } <>2__current = (object)new WaitForSeconds(<latePassDelays>5__2[<i>5__4]); <>1__state = 1; result = true; goto end_IL_0000; IL_01aa: saveManagerPlugin.RestoreWorldObjects(envelope.worldObjects, envelope.formatVersion); ((BaseUnityPlugin)saveManagerPlugin).Logger.LogInfo((object)$"Completed late world reconcile pass {<i>5__4 + 1}/{<latePassDelays>5__2.Length}."); flag = !string.IsNullOrWhiteSpace(saveManagerPlugin.lastGroundRestorePhase) && saveManagerPlugin.lastGroundRestorePhase.StartsWith("late-", StringComparison.OrdinalIgnoreCase); if (<runGroundReconcile>5__5) { <groundSettled>5__3 = flag && saveManagerPlugin.lastGroundRestoreMatchedAllForCurrentPhase && !saveManagerPlugin.lastGroundRestoreHadFailuresForCurrentPhase; } num2 = <groundSettled>5__3 || (!<runGroundReconcile>5__5 && <i>5__4 > 0); ropeLinkRestoreSettledForCurrentLoad = saveManagerPlugin.ropeLinkRestoreSettledForCurrentLoad; if (!(num2 && ropeLinkRestoreSettledForCurrentLoad)) { if (!<runGroundReconcile>5__5 && !ropeLinkRestoreSettledForCurrentLoad) { saveManagerPlugin.LogVerbose($"Late pass {<i>5__4 + 1} kept as rope-only retry. RopeSettled={ropeLinkRestoreSettledForCurrentLoad}"); } else if (<runGroundReconcile>5__5) { saveManagerPlugin.LogVerbose($"Late pass {<i>5__4 + 1} status. GroundSettled={<groundSettled>5__3} " + $"RopeSettled={ropeLinkRestoreSettledForCurrentLoad}"); } <i>5__4++; goto IL_02f5; } goto IL_0308; IL_0308: <>m__Finally1(); result = false; 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; if (reconcileToken == saveManagerPlugin.lateWorldReconcileToken) { saveManagerPlugin.lateWorldReconcileCoroutine = null; } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <StabilizeCharacterAfterLoad>d__266 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Character character; public Vector3 targetPosition; public Vector3 targetEulerRotation; private float <endRealtime>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <StabilizeCharacterAfterLoad>d__266(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; if ((Object)(object)character == (Object)null) { return false; } <endRealtime>5__2 = Time.realtimeSinceStartup + 0.45f; break; case 1: <>1__state = -1; break; } if (Time.realtimeSinceStartup < <endRealtime>5__2) { if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null) { return false; } ResetCharacterLocomotionForLoad(character); ApplyCharacterTransformSnapshot(character, targetPosition, targetEulerRotation); Rigidbody val = ((character.refs != null && (Object)(object)character.refs.hip != (Object)null) ? character.refs.hip.Rig : null); if ((Object)(object)val != (Object)null) { try { val.position = targetPosition; val.rotation = Quaternion.Euler(targetEulerRotation); val.linearVelocity = Vector3.zero; val.angularVelocity = Vector3.zero; } catch { } } <>2__current = null; <>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(); } } [CompilerGenerated] private sealed class <WaitForLoadedSceneWorldReadyRoutine>d__252 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string sceneName; public SaveEnvelope envelope; public SaveManagerPlugin <>4__this; private int <minCampfires>5__2; private int <minLuggage>5__3; private bool <requireSeedConsumption>5__4; private float <timeout>5__5; private float <nextProgressLogAt>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForLoadedSceneWorldReadyRoutine>d__252(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: 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; if (string.IsNullOrWhiteSpace(sceneName)) { return false; } int valueOrDefault = (envelope?.campfires?.Count).GetValueOrDefault(); int valueOrDefault2 = (envelope?.luggageStates?.Count).GetValueOrDefault(); <minCampfires>5__2 = ((valueOrDefault > 0) ? Mathf.Clamp(valueOrDefault / 2, 1, valueOrDefault) : 0); <minLuggage>5__3 = ((valueOrDefault2 > 0) ? Mathf.Clamp(valueOrDefault2 / 3, 4, valueOrDefault2) : 0); <requireSeedConsumption>5__4 = PendingSeedForLoad.HasValue; <timeout>5__5 = 20f; <nextProgressLogAt>5__6 = <timeout>5__5; break; } case 1: <>1__state = -1; break; } if (<timeout>5__5 > 0f) { Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; bool flag = string.Equals(name, sceneName, StringComparison.OrdinalIgnoreCase); bool flag2 = MapHandler.Exists && (Object)(object)Object.FindFirstObjectByType<MapHandler>() != (Object)null; int num2 = SaveManagerPlugin.CountSceneComponents<Campfire>(sceneName); int num3 = SaveManagerPlugin.CountSceneComponents<Luggage>(sceneName); bool flag3 = <minCampfires>5__2 <= 0 || num2 >= <minCampfires>5__2; bool flag4 = <minLuggage>5__3 <= 0 || num3 >= <minLuggage>5__3; bool flag5 = !<requireSeedConsumption>5__4 || PendingSeedConsumedForLoad || PendingSeedStagedForLoad; if (!flag5 && PendingSeedForLoad.HasValue && !PendingSeedStagedForLoad) { saveManagerPlugin.TryForceApplyPendingSeedToGeneration(PendingSeedForLoad.Value, sceneName); } if (flag && flag2 && flag3 && flag4 && flag5) { saveManagerPlugin.LogVerbose($"Loaded scene world ready. Scene='{sceneName}' Campfires={num2}/{Math.Max(<minCampfires>5__2, 0)} " + $"Luggage={num3}/{Math.Max(<minLuggage>5__3, 0)} SeedReady={flag5}"); return false; } if (saveManagerPlugin.IsVerboseLoggingEnabled() && <timeout>5__5 <= <nextProgressLogAt>5__6 - 1f) { <nextProgressLogAt>5__6 = <timeout>5__5; saveManagerPlugin.LogVerbose($"WaitForLoadedSceneWorldReady progress. Remaining={<timeout>5__5:0.##}s ActiveScene='{name}' " + $"SceneMatches={flag} MapHandlerReady={flag2} " + $"Campfires={num2}/{Math.Max(<minCampfires>5__2, 0)} Luggage={num3}/{Math.Max(<minLuggage>5__3, 0)} " + string.Format("SeedReady={0} PendingSeed={1}", flag5, PendingSeedForLoad.HasValue ? PendingSeedForLoad.Value.ToString(CultureInfo.InvariantCulture) : "-")); } <timeout>5__5 -= Time.unscaledDeltaTime; <>2__current = null; <>1__state = 1; return true; } ((BaseUnityPlugin)saveManagerPlugin).Logger.LogWarning((object)("Timed out waiting for loaded scene readiness. Scene='" + Safe(sceneName) + "' " + $"Campfires={SaveManagerPlugin.CountSceneComponents<Campfire>(sceneName)} Luggage={SaveManagerPlugin.CountSceneComponents<Luggage>(sceneName)} " + $"SeedReady={!PendingSeedForLoad.HasValue || PendingSeedConsumedForLoad || PendingSeedStagedForLoad}.")); 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 <WaitForPlayersRoutine>d__256 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float timeoutSeconds; public SaveManagerPlugin <>4__this; public List<PlayerSnapshot> players; private float <timeout>5__2; private float <nextProgressLogAt>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WaitForPlayersRoutine>d__256(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown int num = <>1__state; SaveManagerPlugin saveManagerPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <timeout>5__2 = Mathf.Max(1f, timeoutSeconds); <nextProgressLogAt>5__3 = <timeout>5__2; saveManagerPlugin.LogVerbose($"WaitForPlayersRoutine start. Timeout={<timeout>5__2:0.##}s SnapshotPlayers={players?.Count ?? 0}"); break; case 1: <>1__state = -1; break; } if (<timeout>5__2 > 0f) { int num2 = 0; bool flag = false; if (players != null && players.Count > 0) { for (int i = 0; i < players.Count; i++) { if ((Object)(object)saveManagerPlugin.FindPlayerStrict(players[i]) != (Object)null) { num2++; } } if (num2 > 0) { return false; } if (players.Count == 1 && (Object)(object)FindPrimaryLocalPlayer() != (Object)null) { saveManagerPlugin.LogVerbose("WaitForPlayersRoutine finished via single-player local fallback."); return false; } flag = players.Count == 1 && (Object)(object)FindPrimaryLocalPlayer() != (Object)null; } else if ((Object)(object)FindPrimaryLocalPlayer() != (Object)null) { saveManagerPlugin.LogVerbose("WaitForPlayersRoutine finished via local-player fallback with no snapshot player list."); return false; } if (saveManagerPlugin.IsVerboseLoggingEnabled() && <timeout>5__2 <= <nextProgressLogAt>5__3 - 1f) { <nextProgressLogAt>5__3 = <timeout>5__2; int num3 = Object.FindObjectsByType<Player>((FindObjectsSortMode)0).Count(IsUsablePlayerForRestore); saveManagerPlugin.LogVerbose($"WaitForPlayers progress. Remaining={<timeout>5__2:0.##}s StrictMatched={num2} " + $"LiveUsablePlayers={num3} SinglePlayerFallbackReady={flag}"); } <timeout>5__2 -= Time.deltaTime; <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } saveManagerPlugin.LogVerbose("WaitForPlayersRoutine timed out."); 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.1"; private const string SaveFilePattern = "*.json"; private const int UiWindowId = 129193; private const string PauseMenuButtonObjectName = "PeakSaveManagerButton"; private const float PendingSeedLifetimeSeconds = 90f; private const byte OverflowTempSlotId = 250; private const float ProtectedOverflowDropLifetimeSeconds = 45f; private const float ProtectedOverflowDropRadiusSquared = 4f; private const float PitonNearPlayerDistanceThresholdSqr = 122500f; private const string WorldObjectKindCloudFungus = "CloudFungus"; private const string WorldObjectKindBounceFungus = "BounceFungus"; private const string WorldObjectKindShelfFungus = "ShelfFungus"; 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 MethodInfo LevelGenerationGenerateMethod = AccessTools.Method(typeof(LevelGeneration), "Generate", (Type[])null, (Type[])null); private static readonly MethodInfo LevelGenerationClearMethod = AccessTools.Method(typeof(LevelGeneration), "Clear", (Type[])null, (Type[])null); private static readonly MethodInfo LevelGenerationRandomizeBiomeVariantsMethod = AccessTools.Method(typeof(LevelGeneration), "RandomizeBiomeVariants", (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 = GetPropertySetterOrNull(typeof(RespawnChest), "IsSpent"); private static readonly MethodInfo RespawnChestSetRevivedPlayersMethod = GetPropertySetterOrNull(typeof(RespawnChest), "HasRevivedPlayers") ?? GetPropertySetterOrNull(typeof(RespawnChest), "HasRevived"); private static readonly PropertyInfo RespawnChestIsSpentProperty = GetPropertyOrNull(typeof(RespawnChest), "IsSpent"); private static readonly PropertyInfo RespawnChestHasRevivedPlayersProperty = GetPropertyOrNull(typeof(RespawnChest), "HasRevivedPlayers") ?? GetPropertyOrNull(typeof(RespawnChest), "HasRevived"); 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 MethodInfo CharacterDataSetSkeletonMethod = AccessTools.Method(typeof(CharacterData), "SetSkeleton", new Type[1] { typeof(bool) }, (Type[])null); private static readonly MethodInfo CharacterDataSyncSkeletonMethod = AccessTools.Method(typeof(CharacterData), "RPC_SyncSkeleton", new Type[1] { typeof(bool) }, (Type[])null); private static readonly FieldInfo CharacterDataIsSkeletonField = AccessTools.Field(typeof(CharacterData), "_isSkeleton"); 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 MethodInfo RopeAnchorProjectileGetShotMethod = AccessTools.Method(typeof(RopeAnchorProjectile), "GetShot", new Type[4] { typeof(Vector3), typeof(float), typeof(float), typeof(Vector3) }, (Type[])null); private static readonly Type AirportCheckInKioskType = AccessTools.TypeByName("AirportCheckInKiosk"); private static readonly MethodInfo AirportCheckInKioskBeginIslandLoadRpcMethod = ((AirportCheckInKioskType != null) ? AccessTools.Method(AirportCheckInKioskType, "BeginIslandLoadRPC", new Type[2] { typeof(string), typeof(int) }, (Type[])null) : null); private static readonly Type MapGeneratorType = AccessTools.TypeByName("MapGenerator"); private static readonly MethodInfo MapGeneratorGenerateAllMethod = ((MapGeneratorType != null) ? AccessTools.Method(MapGeneratorType, "GenerateAll", (Type[])null, (Type[])null) : null); private static readonly MethodInfo MapGeneratorClearAllMethod = ((MapGeneratorType != null) ? AccessTools.Method(MapGeneratorType, "ClearAll", (Type[])null, (Type[])null) : null); private static readonly FieldInfo MapGeneratorSeedField = ((MapGeneratorType != null) ? AccessTools.Field(MapGeneratorType, "seed") : null); private static readonly FieldInfo LoadingScreenHandlerLoadingField = GetFieldOrNull(typeof(LoadingScreenHandler), "loading"); private static readonly PropertyInfo LoadingScreenHandlerLoadingProperty = GetPropertyOrNull(typeof(LoadingScreenHandler), "loading"); private static readonly Dictionary<int, float> RopeVisualizerCorrectionUntilRealtime = new Dictionary<int, float>(); private static readonly FieldInfo RopeAnchorProjectileLastShotToField = AccessTools.Field(typeof(RopeAnchorProjectile), "lastShotTo"); private static readonly FieldInfo RopeAnchorProjectileLastShotTravelTimeField = AccessTools.Field(typeof(RopeAnchorProjectile), "lastShotTravelTime"); private static readonly FieldInfo RopeAnchorProjectileLastShotRopeLengthField = AccessTools.Field(typeof(RopeAnchorProjectile), "lastShotRopeLength"); private static readonly FieldInfo RopeAnchorProjectileLastShotFlyingRotationField = AccessTools.Field(typeof(RopeAnchorProjectile), "lastShotFlyingRotation"); private static readonly FieldInfo RopeAttachedToAnchorField = AccessTools.Field(typeof(Rope), "attachedToAnchor"); private static readonly FieldInfo RopeSpoolField = AccessTools.Field(typeof(Rope), "spool"); private static readonly MethodInfo RopeAttachToAnchorRpcMethod = AccessTools.Method(typeof(Rope), "AttachToAnchor_Rpc", new Type[2] { typeof(PhotonView), typeof(float) }, (Type[])null); private static readonly MethodInfo RopeAttachToSpoolRpcMethod = AccessTools.Method(typeof(Rope), "AttachToSpool_Rpc", new Type[1] { typeof(PhotonView) }, (Type[])null); private static readonly MethodInfo RopeGetLengthInMetersMethod = AccessTools.Method(typeof(Rope), "GetLengthInMeters", (Type[])null, (Type[])null); private static readonly MethodInfo RopeSegmentTieMethod = AccessTools.Method(typeof(RopeSegment), "Tie", new Type[1] { typeof(Vector3) }, (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 MethodInfo MagicBeanVineFixedUpdateMethod = AccessTools.Method(typeof(MagicBeanVine), "FixedUpdate", (Type[])null, (Type[])null); 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 FieldInfo CharacterItemsMaxSlotField = AccessTools.Field(typeof(CharacterItems), "MAX_SLOT"); private static readonly FieldInfo PlayerLocalPlayerField = AccessTools.Field(typeof(Player), "localPlayer"); private static readonly MethodInfo CharacterItemsEquipSlotMethod = AccessTools.Method(typeof(CharacterItems), "EquipSlot", new Type[1] { typeof(Optionable<byte>) }, (Type[])null); private static readonly MethodInfo CharacterItemsEquipItemMethod = AccessTools.Method(typeof(CharacterItems), "Equip", new Type[1] { typeof(Item) }, (Type[])null); private static readonly MethodInfo CharacterItemsDropItemFromSlotRpcMethod = AccessTools.Method(typeof(CharacterItems), "DropItemFromSlotRPC", new Type[2] { typeof(byte), typeof(Vector3) }, (Type[])null); private static readonly ConstructorInfo OptionableByteConstructor = AccessTools.Constructor(typeof(Optionable<byte>), new Type[2] { typeof(byte), typeof(byte) }, false); private static readonly PropertyInfo PhotonViewInstantiationIdProperty = GetPropertyOrNull(typeof(PhotonView), "InstantiationId"); private static readonly PropertyInfo PhotonViewIsSceneViewProperty = GetPropertyOrNull(typeof(PhotonView), "IsSceneView"); private static readonly FieldInfo OptionableByteHasValueField = AccessTools.Field(typeof(Optionable<byte>), "hasValue"); private static readonly FieldInfo OptionableByteValueField = AccessTools.Field(typeof(Optionable<byte>), "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 HashSet<STATUSTYPE> SkippedSavedStatuses = new HashSet<STATUSTYPE> { (STATUSTYPE)7 }; private static readonly HashSet<DataEntryKey> ExplicitItemDataKeys = new HashSet<DataEntryKey> { (DataEntryKey)2, (DataEntryKey)12, (DataEntryKey)11, (DataEntryKey)8, (DataEntryKey)10, (DataEntryKey)1, (DataEntryKey)3, (DataEntryKey)13, (DataEntryKey)5, (DataEntryKey)7 }; private static SaveManagerPlugin Instance; private static int? PendingSeedForLoad; private static float PendingSeedSetRealtime; private static bool PendingSeedConsumedForLoad; private static bool PendingSeedStagedForLoad; private static int? ForcedDailyLevelIndexForLoad; private static bool ForcedDailyLevelIndexLogEmitted; private Harmony harmony; private ConfigEntry<bool> autoSaveEnabled; private ConfigEntry<float> autoSaveIntervalSeconds; private ConfigEntry<bool> verboseLogging; private string saveDirectory; private bool showUi; private bool isLoading; private float loadStartedRealtime = -1f; private bool ropeLinkRestoreSettledForCurrentLoad; private float lastRopeLinkRestoreRealtime = -1f; private int lastRopeLinkExpectedCount = -1; private int lastRopeLinkResolvedCount = -1; private Coroutine lateWorldReconcileCoroutine; private Coroutine deferredGroundRestoreCoroutine; private int lateWorldReconcileToken; private string lastGroundRestorePhase = string.Empty; private bool lastGroundRestoreMatchedAllForCurrentPhase; private bool lastGroundRestoreHadFailuresForCurrentPhase; 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<SaveListEntry> saveEntries = new List<SaveListEntry>(); private readonly Dictionary<int, int> overflowTempEquipGenerationByPlayer = new Dictionary<int, int>(); private readonly List<ProtectedGroundItemMarker> protectedGroundItemMarkers = new List<ProtectedGroundItemMarker>(); 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) Instance = this; autoSaveEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoSave", "Enable AutoSave", true, "Automatically create rolling autosaves"); autoSaveIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("AutoSave", "Interval Seconds", 300f, "Seconds between autosaves"); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Verbose Logging", true, "Enable detailed save/load diagnostics."); saveDirectory = Path.Combine(Paths.GameRootPath, "PeakSaves"); if (!Directory.Exists(saveDirectory)) { Directory.CreateDirectory(saveDirectory); } harmony = new Harmony("com.lucasandersen.peakallyouneedsavemanager"); harmony.PatchAll(); InstallRuntimeCompatibilityPatches(); RefreshSaveFileList(); SetStatus("Save manager ready.", Color.cyan, 2f); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded The All You Need Save Manager 1.0.1 by Lucas Andersen"); LogVerbose("Verbose logging enabled. SaveDir='" + saveDirectory + "'"); } 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}"); } overflowTempEquipGenerationByPlayer.Clear(); protectedGroundItemMarkers.Clear(); DestroyUiResources(); } private void InstallRuntimeCompatibilityPatches() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { if (MapGeneratorGenerateAllMethod == null) { LogVerbose("MapGenerator.GenerateAll not found; skipping runtime seed compatibility patch."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(SaveManagerPlugin), "MapGeneratorGenerateAllPrefix", (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"MapGenerator compatibility prefix method could not be resolved."); return; } harmony.Patch((MethodBase)MapGeneratorGenerateAllMethod, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); LogVerbose("Applied runtime seed compatibility patch to MapGenerator.GenerateAll."); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to apply MapGenerator runtime compatibility patch: " + ex.Message)); } } 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<GUILayoutOption>()); 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<GUILayoutOption>()); GUILayout.Label("Create Save", subtitleStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); if (flag) { GUILayout.Label("You cannot save in the Airport.", errorLabelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Space(4f); } GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); 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<GUILayoutOption>()); 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<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label("Saved Runs", subtitleStyle, Array.Empty<GUILayoutOption>()); 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<GUILayoutOption>()); } else { foreach (SaveListEntry saveEntry in saveEntries) { DrawSaveCard(saveEntry); GUILayout.Space(5f); } } GUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.Space(8f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); 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) { GUILayout.BeginVertical(entry.isCompatible ? cardStyle : cardWarningStyle, Array.Empty<GUILayoutOption>()); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(entry.fileName, titleStyle, Array.Empty<GUILayoutOption>()); 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<GUILayoutOption>()); GUILayout.Label("Level: " + text2 + " Segment: " + Safe(ToDisplaySegmentName(entry.metadata.currentSegmentName, entry.metadata.biomeId)), normalLabelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Seed: {entry.metadata.levelSeed} Ascent: {entry.metadata.ascent} Players: {num}", normalLabelStyle, Array.Empty<GUILayoutOption>()); GUILayout.Label(FormatRunSummary(entry.metadata), normalLabelStyle, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label($"File Time: {entry.fileTime:yyyy-MM-dd HH:mm:ss}", normalLabelStyle, Array.Empty<GUILayoutOption>()); } if (!entry.isCompatible) { GUILayout.Label("Incompatible: " + entry.incompatibilityReason, errorLabelStyle, Array.Empty<GUILayoutOption>()); } GUILayout.Space(4f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); 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; if (GUILayout.Button("Overwrite", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Height(24f), GUILayout.Width(100f) })) { if (!CanSaveNow(showReason: true)) { GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.EndVertical(); return; } 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)) { LogVerbose("StartLoadFromUi ignored due to empty path."); return; } LogVerbose("StartLoadFromUi path='" + fullPath + "'"); showUi = false; ClearPendingConfirmation(); pauseMenuPage?.PrepareForLoad(); ClosePauseMenuForLoad(); ((MonoBehaviour)this).StartCoroutine(LoadSaveRoutine(fullPath)); } private void ClosePauseMenuForLoad() { try { if ((Object)(object)EventSystem.current != (Objec