Decompiled source of The All You Need Save Manager v1.0.3
BepInEx\plugins\TAYNSM\TAYNSM.dll
Decompiled 3 weeks 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