Decompiled source of The All You Need Save Manager Continued v1.2.5

BepInEx/plugins/PeakSaveManagerContinued/PeakSaveManagerContinued.dll

Decompiled 2 weeks ago
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 ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Peak;
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: AssemblyCompany("PeakSaveManagerContinued")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.5.0")]
[assembly: AssemblyInformationalVersion("1.2.5+899267627bec39bd5d3ffc227a62a65517dfbd2f")]
[assembly: AssemblyProduct("The All You Need Save Manager Continued")]
[assembly: AssemblyTitle("PeakSaveManagerContinued")]
[assembly: AssemblyVersion("1.2.5.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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
{
	internal static class ItemUsesRestoration
	{
		internal static OptionableIntItemData Normalize(DataEntryValue value)
		{
			OptionableIntItemData val = (OptionableIntItemData)(object)((value is OptionableIntItemData) ? value : null);
			if (val != null)
			{
				return val;
			}
			IntItemData val2 = (IntItemData)(object)((value is IntItemData) ? value : null);
			if (val2 == null)
			{
				return null;
			}
			return FromLegacy(val2.Value);
		}

		internal static void ApplyLegacy(ItemInstanceData data, int? itemUses, bool restoredGenericItemUses)
		{
			if (!(data == null || restoredGenericItemUses) && itemUses.HasValue)
			{
				if (data.data == null)
				{
					data.data = new Dictionary<DataEntryKey, DataEntryValue>();
				}
				data.data[(DataEntryKey)2] = (DataEntryValue)(object)FromLegacy(itemUses.Value);
			}
		}

		private static OptionableIntItemData FromLegacy(int value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			return new OptionableIntItemData
			{
				HasData = (value >= 0),
				Value = Math.Max(-1, value)
			};
		}
	}
	internal static class LandingSelection
	{
		internal const float HorizontalLimit = 8f;

		internal const float VerticalLimit = 8f;

		internal const float DistanceLimit = 10f;

		internal const float MinimumNormalY = 0.819152f;

		internal static bool NeedsSupport(CharacterSnapshot saved)
		{
			if (saved != null && saved.isGrounded && !saved.dead && !saved.passedOut && !saved.fullyPassedOut && !saved.isClimbing && !saved.isRopeClimbing)
			{
				return !saved.isVineClimbing;
			}
			return false;
		}

		internal static bool IsSupportSample(float belowTorso, float torsoHeight, float normalY, bool preserveOriginal)
		{
			if (normalY >= 0.819152f && belowTorso >= 0.65f)
			{
				return belowTorso <= torsoHeight + (preserveOriginal ? 0.15f : 0.3f);
			}
			return false;
		}

		internal static double DistanceSquared(Vector3Snapshot a, Vector3Snapshot b)
		{
			double num = (double)a.x - (double)b.x;
			double num2 = (double)a.y - (double)b.y;
			double num3 = (double)a.z - (double)b.z;
			return num * num + num2 * num2 + num3 * num3;
		}

		internal static Vector3Snapshot Closest(Vector3Snapshot original, IEnumerable<Vector3Snapshot> safeCandidates)
		{
			Vector3Snapshot result = null;
			double num = double.PositiveInfinity;
			foreach (Vector3Snapshot safeCandidate in safeCandidates)
			{
				if (safeCandidate != null)
				{
					double num2 = (double)safeCandidate.x - (double)original.x;
					double num3 = (double)safeCandidate.z - (double)original.z;
					double num4 = DistanceSquared(original, safeCandidate);
					if (!double.IsNaN(num4) && !double.IsInfinity(num4) && !(num2 * num2 + num3 * num3 > 64.0) && !(Math.Abs((double)safeCandidate.y - (double)original.y) > 8.0) && !(num4 > 100.0) && !(num4 >= num))
					{
						result = safeCandidate;
						num = num4;
					}
				}
			}
			return result;
		}
	}
	[BepInPlugin("com.lucasandersen.peakallyouneedsavemanager", "The All You Need Save Manager Continued", "1.2.5")]
	public sealed class SaveManagerPlugin : BaseUnityPlugin, IOnEventCallback
	{
		private sealed class LuggageBatch
		{
			public string scene;

			public long revision;

			public List<LuggageRestoreState> states = new List<LuggageRestoreState>();
		}

		private sealed class UnityLuggageRestoreTarget : ILuggageRestoreTarget
		{
			private readonly Luggage luggage;

			internal UnityLuggageRestoreTarget(Luggage luggage)
			{
				this.luggage = luggage;
			}

			public void CancelOpening()
			{
				((MonoBehaviour)luggage).StopAllCoroutines();
			}

			public void ResetSpawnHistory()
			{
				SpawnedItemTracker component = ((Component)luggage).GetComponent<SpawnedItemTracker>();
				if (!((Object)(object)component == (Object)null))
				{
					SpawnHistoryField.SetValue(component, null);
					(SpawnedItemsField.GetValue(component) as IList)?.Clear();
					SetSpawnHistoryMethod.Invoke(component, new object[1] { false });
				}
			}

			public void SetOpen(bool open)
			{
				LuggageStateField.SetValue(luggage, Enum.ToObject(LuggageStateField.FieldType, open ? 1 : 0));
			}

			public void SetVisual(bool open)
			{
				Animator component = ((Component)luggage).GetComponent<Animator>();
				if ((Object)(object)component == (Object)null || (Object)(object)component.runtimeAnimatorController == (Object)null)
				{
					throw new InvalidOperationException("A restored luggage has no animator.");
				}
				if (open && !component.HasState(0, Animator.StringToHash("Luggage_Open")))
				{
					throw new InvalidOperationException("The game's luggage opening animation changed.");
				}
				bool fireEvents = component.fireEvents;
				component.fireEvents = false;
				try
				{
					component.Rebind();
					if (open)
					{
						component.Play("Luggage_Open", 0, 1f);
					}
					component.Update(0f);
				}
				finally
				{
					component.fireEvents = fireEvents;
				}
			}

			public void SetAvailable(bool available)
			{
				while (Luggage.ALL_LUGGAGE.Remove(luggage))
				{
				}
				if (available)
				{
					Luggage.ALL_LUGGAGE.Add(luggage);
				}
				luggage.HoverExit();
			}

			public void SetActivatedObject(bool active)
			{
				if ((Object)(object)luggage.activateOnOpen != (Object)null)
				{
					luggage.activateOnOpen.SetActive(active);
				}
			}

			public void SetRevivalState(bool spent, bool revivedPlayers)
			{
				Luggage obj = luggage;
				RespawnChest val = (RespawnChest)(object)((obj is RespawnChest) ? obj : null);
				if (val != null)
				{
					SetRespawnChestState(val, spent, revivedPlayers);
					if ((Object)(object)val.skeleton != (Object)null)
					{
						val.skeleton.SetActive(!revivedPlayers);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Luggage), "OnCharacterRegistered")]
		private static class RestoredLuggageJoinPatch
		{
			private static void Postfix(Luggage __instance, Character __0)
			{
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_006a: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Instance == (Object)null || !PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || !Instance.restoredLuggage.Contains(__instance) || !((Component)__instance).gameObject.activeInHierarchy)
				{
					return;
				}
				PhotonView photonView = GetPhotonView((Component)(object)__0);
				if (((photonView != null) ? photonView.Owner : null) == null || photonView.Owner.IsLocal)
				{
					return;
				}
				try
				{
					LuggageBatch luggageBatch = new LuggageBatch();
					Scene activeScene = SceneManager.GetActiveScene();
					luggageBatch.scene = ((Scene)(ref activeScene)).name;
					luggageBatch.revision = ++Instance.luggageRevision;
					LuggageBatch luggageBatch2 = luggageBatch;
					luggageBatch2.states.Add(CaptureLiveLuggage(__instance));
					SendPlayerLoadEvent(photonView.OwnerActorNr, "luggage", Guid.NewGuid().ToString("N"), 0, PhotonNetwork.ServerTimestamp + 30000, JsonConvert.SerializeObject((object)luggageBatch2));
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)Instance).Logger.LogWarning((object)("Could not sync restored luggage to a joining player: " + ex.Message));
				}
			}
		}

		private sealed class OwnerLoadReply
		{
			internal int actor;

			internal int viewId;

			internal bool completed;

			internal string error;
		}

		private sealed class UnityPlayerLoadTarget : IPlayerLoadTarget, IPlayerLandingTarget
		{
			private static readonly FieldInfo WarpRoutineField = AccessTools.Field(typeof(Character), "_warpRoutine");

			private static readonly WarpStatusLock StatusLock = new WarpStatusLock(typeof(Character));

			private static readonly MethodInfo SetWarpingMethod = AccessTools.PropertySetter(typeof(Character), "warping");

			private readonly Character character;

			private readonly PlayerSnapshot snapshot;

			private readonly Func<bool> requestIsCurrent;

			private readonly PhotonView view;

			private readonly byte? selectedSlot;

			private readonly List<KeyValuePair<Collider, bool>> collisionBeforeWarp = new List<KeyValuePair<Collider, bool>>();

			private Coroutine ownedWarp;

			private bool warpCompleted;

			private bool equipmentStarted;

			public bool IsAvailable
			{
				get
				{
					if ((Object)(object)character != (Object)null && character.IsLocal && (Object)(object)character.player != (Object)null && (Object)(object)character.data != (Object)null && (Object)(object)character.refs?.ragdoll != (Object)null && (Object)(object)character.refs.items != (Object)null && ((Object)(object)view == (Object)null || view.IsMine) && requestIsCurrent())
					{
						if (ownedWarp != null)
						{
							return WarpRoutineField.GetValue(character) == ownedWarp;
						}
						return true;
					}
					return false;
				}
			}

			public float Realtime => Time.realtimeSinceStartup;

			public bool IsWarping
			{
				get
				{
					if ((Object)(object)character != (Object)null)
					{
						return character.warping;
					}
					return false;
				}
			}

			public bool WarpCompleted => warpCompleted;

			public bool IsAtDestination
			{
				get
				{
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0024: Unknown result type (might be due to invalid IL or missing references)
					if ((Object)(object)character != (Object)null)
					{
						return Vector3.Distance(character.Center, snapshot.position.ToUnity()) <= 0.75f;
					}
					return false;
				}
			}

			public bool RequiresStableLanding => LandingSelection.NeedsSupport(snapshot.character);

			public bool IsLandingStable
			{
				get
				{
					//IL_0066: Unknown result type (might be due to invalid IL or missing references)
					//IL_006b: Unknown result type (might be due to invalid IL or missing references)
					if (!IsAvailable || !character.data.isGrounded || !IsAtDestination)
					{
						return false;
					}
					foreach (Bodypart part in character.refs.ragdoll.partList)
					{
						if ((Object)(object)part != (Object)null && (Object)(object)part.Rig != (Object)null)
						{
							Vector3 linearVelocity = part.Rig.linearVelocity;
							if (((Vector3)(ref linearVelocity)).sqrMagnitude > 2.25f)
							{
								return false;
							}
						}
					}
					return true;
				}
			}

			public bool IsEquipmentReady
			{
				get
				{
					//IL_0080: Unknown result type (might be due to invalid IL or missing references)
					//IL_0085: Unknown result type (might be due to invalid IL or missing references)
					if (!IsAvailable)
					{
						return false;
					}
					Item currentItem = character.data.currentItem;
					if (!selectedSlot.HasValue)
					{
						return (Object)(object)currentItem == (Object)null;
					}
					if (equipmentStarted && !((Object)(object)currentItem == (Object)null) && !((Object)(object)currentItem.rig == (Object)null) && !((Object)(object)currentItem.holderCharacter != (Object)(object)character) && currentItem.itemID == snapshot.inventory.heldItemId)
					{
						Scene scene = ((Component)currentItem).gameObject.scene;
						if (((Scene)(ref scene)).IsValid())
						{
							if (HasItemJoint((BodypartType)10, currentItem.rig))
							{
								if (!currentItem.rightHandOnly)
								{
									return HasItemJoint((BodypartType)7, currentItem.rig);
								}
								return true;
							}
							return false;
						}
					}
					return false;
				}
			}

			internal UnityPlayerLoadTarget(Character character, PlayerSnapshot snapshot, Func<bool> requestIsCurrent)
			{
				this.character = character;
				this.snapshot = snapshot;
				this.requestIsCurrent = requestIsCurrent;
				view = GetPhotonView((Component)(object)character);
				selectedSlot = PlayerLoadRestoration.ResolveEquippedSlot(snapshot.inventory, (character.player?.itemSlots?.Length).GetValueOrDefault(), delegate(byte slot)
				{
					Player player = character.player;
					if (player == null)
					{
						return (ushort?)null;
					}
					ItemSlot itemSlot = player.GetItemSlot(slot);
					return (itemSlot == null) ? ((ushort?)null) : itemSlot.prefab?.itemID;
				});
				if (snapshot.inventory != null && snapshot.inventory.heldItemId != ushort.MaxValue && !selectedSlot.HasValue)
				{
					SaveManagerPlugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogWarning((object)$"Saved held item {snapshot.inventory.heldItemId} is absent from native equippable slots; restoring empty hands.");
					}
				}
			}

			private bool HasItemJoint(BodypartType part, Rigidbody itemRig)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				foreach (Bodypart part2 in character.refs.ragdoll.partList)
				{
					if ((Object)(object)part2 == (Object)null || part2.partType != part || (Object)(object)part2.Rig == (Object)null)
					{
						continue;
					}
					FixedJoint[] components = ((Component)part2.Rig).GetComponents<FixedJoint>();
					for (int i = 0; i < components.Length; i++)
					{
						if ((Object)(object)((Joint)components[i]).connectedBody == (Object)(object)itemRig)
						{
							return true;
						}
					}
				}
				return false;
			}

			public void ClearHeldItem()
			{
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				CharacterItems items = character.refs.items;
				Item currentItem = character.data.currentItem;
				PhotonView val = (((Object)(object)currentItem != (Object)null) ? GetPhotonView((Component)(object)currentItem) : null);
				if ((Object)(object)currentItem != (Object)null)
				{
					if (!((Object)(object)currentItem.rig == (Object)null))
					{
						Scene scene = ((Component)currentItem).gameObject.scene;
						if (((Scene)(ref scene)).IsValid() && (!PhotonNetwork.InRoom || (!((Object)(object)val == (Object)null) && val.ViewID != 0)))
						{
							goto IL_0080;
						}
					}
					items.UnAttachEquippedItem();
				}
				goto IL_0080;
				IL_0080:
				items.currentSelectedSlot = Optionable<byte>.None;
				PhotonView photonView = GetPhotonView((Component)(object)items);
				if ((Object)(object)photonView != (Object)null)
				{
					photonView.RPC("EquipSlotRpc", (RpcTarget)0, new object[2] { -1, -1 });
				}
				else
				{
					items.EquipSlotRpc(-1, -1);
				}
			}

			public void ApplyLook()
			{
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				((Component)character).transform.eulerAngles = snapshot.rotation.ToUnity();
				character.data.lookValues = snapshot.character.lookValues.ToUnity();
				RecalculateLookDirectionsMethod.Invoke(character, null);
			}

			public void BeginWarp()
			{
				//IL_0099: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Expected O, but got Unknown
				if (WarpRoutineField == null || !StatusLock.IsSupported || SetWarpingMethod == null)
				{
					throw new InvalidOperationException("The game's teleport cleanup API changed.");
				}
				Collider[] componentsInChildren = ((Component)character.refs.ragdoll).GetComponentsInChildren<Collider>(true);
				foreach (Collider val in componentsInChildren)
				{
					collisionBeforeWarp.Add(new KeyValuePair<Collider, bool>(val, val.enabled));
				}
				character.WarpCompleted += OnWarpCompleted;
				character.WarpPlayerRPC(snapshot.position.ToUnity(), false);
				ownedWarp = (Coroutine)WarpRoutineField.GetValue(character);
			}

			private void OnWarpCompleted(Character source)
			{
				if ((Object)(object)source == (Object)(object)character && ownedWarp != null && WarpRoutineField.GetValue(character) == ownedWarp)
				{
					warpCompleted = true;
				}
			}

			public void RestoreLifeState()
			{
				CharacterSnapshot characterSnapshot = snapshot.character;
				character.data.dead = characterSnapshot.dead;
				character.data.passedOut = characterSnapshot.passedOut;
				character.data.fullyPassedOut = characterSnapshot.fullyPassedOut;
				character.data.deathTimer = (characterSnapshot.dead ? 1f : 0f);
				character.data.SetPetrify(PlayerRestoration.GetSavedPetrify(characterSnapshot.statuses));
				character.refs.ragdoll.ToggleCollision(!characterSnapshot.dead);
				ApplyCharacterStatuses(character, characterSnapshot.statuses);
				character.SetExtraStamina(characterSnapshot.extraStamina);
				character.data.currentStamina = characterSnapshot.currentStamina;
				character.data.PushAll();
			}

			public void HaltMotion()
			{
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
				character.refs.ragdoll.HaltBodyVelocity(true);
				character.data.avarageVelocity = Vector3.zero;
				character.data.avarageLastFrameVelocity = Vector3.zero;
				character.data.fallSeconds = 0f;
				Item currentItem = character.data.currentItem;
				if ((Object)(object)currentItem != (Object)null && (Object)(object)currentItem.rig != (Object)null && !currentItem.rig.isKinematic)
				{
					currentItem.rig.linearVelocity = Vector3.zero;
					currentItem.rig.angularVelocity = Vector3.zero;
				}
			}

			public void EquipSavedSlot()
			{
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				if (selectedSlot.HasValue)
				{
					character.refs.items.EquipSlot(Optionable<byte>.Some(selectedSlot.Value));
					character.refs.items.LockFromSwitching(5f);
					equipmentStarted = true;
				}
			}

			public void Finish(bool succeeded)
			{
				if ((Object)(object)character == (Object)null)
				{
					return;
				}
				character.WarpCompleted -= OnWarpCompleted;
				if (equipmentStarted && (Object)(object)character.refs?.items != (Object)null)
				{
					character.refs.items.lastEquippedSlotTime = Time.time;
				}
				if (succeeded || ownedWarp == null || !character.warping || WarpRoutineField.GetValue(character) != ownedWarp)
				{
					return;
				}
				((MonoBehaviour)character).StopCoroutine(ownedWarp);
				SetWarpingMethod.Invoke(character, new object[1] { false });
				StatusLock.Release(character);
				foreach (KeyValuePair<Collider, bool> item in collisionBeforeWarp)
				{
					if ((Object)(object)item.Key != (Object)null)
					{
						item.Key.enabled = item.Value;
					}
				}
				if ((Object)(object)character.refs?.ragdoll != (Object)null)
				{
					HaltMotion();
				}
			}
		}

		private sealed class SavedMapLoader : ISavedMapLoader
		{
			private MapBundleData bundle;

			public float Realtime => Time.realtimeSinceStartup;

			public bool IsLoading
			{
				get
				{
					if (bundle != null)
					{
						return bundle.Loading;
					}
					return false;
				}
			}

			public bool CanLoad(string sceneName)
			{
				return Application.CanStreamedLevelBeLoaded(sceneName);
			}

			public bool BeginBundleLoad(int levelNumber)
			{
				MapBundleService service = GameHandler.GetService<MapBundleService>();
				bundle = ((service != null) ? service.LoadBundlesNearestIndex(levelNumber, false) : null);
				return bundle != null;
			}
		}

		private sealed class ScenePreparationRequest
		{
			public string session;

			public string scene;

			public int seed;

			public int ascent;

			public int[] actors;
		}

		private sealed class SharedScenePreparation
		{
			internal ScenePreparationRequest Request;

			internal SceneLoadParty Party;

			internal Room Room;

			internal string SourceScene;

			internal int ExpiresAt;

			internal int PreviousAscent;

			internal bool Prepared;

			internal bool Armed;

			internal bool Busy;

			internal bool AddedSceneSwitchingStatus;

			internal Exception LoadError;
		}

		private readonly HashSet<Luggage> restoredLuggage = new HashSet<Luggage>();

		private readonly HashSet<string> worldRestoreWarnings = new HashSet<string>();

		private readonly LuggageRevisions receivedLuggageRevisions = new LuggageRevisions();

		private long luggageRevision;

		private static readonly FieldInfo SpawnHistoryField = AccessTools.Field(typeof(SpawnedItemTracker), "_historyFromSave");

		private static readonly FieldInfo SpawnedItemsField = AccessTools.Field(typeof(SpawnedItemTracker), "_spawnedItems");

		private static readonly MethodInfo SetSpawnHistoryMethod = AccessTools.PropertySetter(typeof(SpawnedItemTracker), "HasSpawnHistory");

		private readonly List<string> landingRestoreWarnings = new List<string>();

		private static readonly FieldInfo ConditionalStandableField = AccessTools.Field(typeof(CollisionModifier), "hasStandableRange");

		private const byte PlayerLoadEventCode = 173;

		private const int PlayerLoadProtocol = 6;

		private const int PlayerLoadRequestLifetimeMs = 30000;

		private readonly Dictionary<string, OwnerLoadReply> ownerLoadReplies = new Dictionary<string, OwnerLoadReply>();

		private readonly HashSet<int> ownerLoadsInProgress = new HashSet<int>();

		public const string PluginGuid = "com.lucasandersen.peakallyouneedsavemanager";

		public const string PluginName = "The All You Need Save Manager Continued";

		public const string PluginVersion = "1.2.5";

		private const string SaveFilePattern = "*.json";

		private const int UiWindowId = 129193;

		private const string PauseMenuButtonObjectName = "PeakSaveManagerButton";

		private const float PendingSeedLifetimeSeconds = 90f;

		private static readonly MethodInfo RecalculateLookDirectionsMethod = AccessTools.Method(typeof(Character), "RecalculateLookDirections", (Type[])null, (Type[])null);

		private static readonly MethodInfo CampfireUpdateLitMethod = AccessTools.Method(typeof(Campfire), "UpdateLit", (Type[])null, (Type[])null);

		private static readonly MethodInfo CampfireHideLogsMethod = AccessTools.Method(typeof(Campfire), "HideLogs", (Type[])null, (Type[])null);

		private static readonly FieldInfo LuggageStateField = AccessTools.Field(typeof(Luggage), "state");

		private static readonly MethodInfo MenuWindowOpenMethod = AccessTools.Method(typeof(MenuWindow), "Open", (Type[])null, (Type[])null);

		private static readonly MethodInfo MenuWindowCloseMethod = AccessTools.Method(typeof(MenuWindow), "Close", (Type[])null, (Type[])null);

		private static readonly MethodInfo RespawnChestSetSpentMethod = AccessTools.PropertySetter(typeof(RespawnChest), "IsSpent");

		private static readonly MethodInfo RespawnChestSetRevivedPlayersMethod = AccessTools.PropertySetter(typeof(RespawnChest), "HasRevivedPlayers");

		private static readonly MethodInfo RespawnChestGetRevivedPlayersMethod = AccessTools.PropertyGetter(typeof(RespawnChest), "HasRevivedPlayers");

		private static readonly FieldInfo RespawnChestRevivedPlayersField = AccessTools.Field(typeof(RespawnChest), "hasRevivedPlayers");

		private static readonly MethodInfo RunManagerRpcSyncTimeMethod = AccessTools.Method(typeof(RunManager), "RPC_SyncTime", new Type[2]
		{
			typeof(float),
			typeof(bool)
		}, (Type[])null);

		private static readonly FieldInfo RunManagerTimeSinceRunStartedField = AccessTools.Field(typeof(RunManager), "timeSinceRunStarted");

		private static readonly FieldInfo RunManagerTimerActiveField = AccessTools.Field(typeof(RunManager), "timerActive");

		private static readonly PropertyInfo RopeShooterAmmoProperty = AccessTools.Property(typeof(RopeShooter), "Ammo");

		private static readonly MethodInfo RopeShooterSyncRpcMethod = AccessTools.Method(typeof(RopeShooter), "Sync_Rpc", new Type[1] { typeof(bool) }, (Type[])null);

		private static readonly FieldInfo ItemTotalUsesField = AccessTools.Field(typeof(Item), "totalUses");

		private static readonly FieldInfo ItemDataField = AccessTools.Field(typeof(Item), "data");

		private static readonly FieldInfo MagicBeanVineCurrentLengthField = AccessTools.Field(typeof(MagicBeanVine), "currentLength");

		private static readonly FieldInfo MagicBeanVineInitialLengthField = AccessTools.Field(typeof(MagicBeanVine), "initialLength");

		private static readonly FieldInfo MagicBeanVineMaxLengthField = AccessTools.Field(typeof(MagicBeanVine), "maxLength");

		private static readonly FieldInfo CloudFungusAlreadyBrokeField = AccessTools.Field(typeof(CloudFungus), "alreadyBroke");

		private static readonly FieldInfo CloudFungusTimeAliveField = AccessTools.Field(typeof(CloudFungus), "timeAlive");

		private static readonly FieldInfo OptionableIntHasDataField = AccessTools.Field(typeof(OptionableIntItemData), "HasData");

		private static readonly FieldInfo OptionableIntValueField = AccessTools.Field(typeof(OptionableIntItemData), "Value");

		private static readonly FieldInfo OptionableBoolHasDataField = AccessTools.Field(typeof(OptionableBoolItemData), "HasData");

		private static readonly FieldInfo OptionableBoolValueField = AccessTools.Field(typeof(OptionableBoolItemData), "Value");

		private static readonly FieldInfo CharacterDataCheckpointFlagsField = AccessTools.Field(typeof(CharacterData), "checkpointFlags");

		private static readonly FieldInfo CheckpointFlagStatusesField = AccessTools.Field(typeof(CheckpointFlag), "currentStatuses");

		private static readonly FieldInfo CheckpointFlagPlanterField = AccessTools.Field(typeof(CheckpointFlag), "planterCharacter");

		private static readonly FieldInfo CharacterItemsCurrentSelectedSlotField = AccessTools.Field(typeof(CharacterItems), "currentSelectedSlot");

		private static readonly 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 MethodInfo DayNightTimeStringGetterMethod = AccessTools.PropertyGetter(typeof(DayNightManager), "timeString");

		private static readonly MethodInfo DayNightTimeStringSetterMethod = AccessTools.PropertySetter(typeof(DayNightManager), "timeString");

		private static readonly FieldInfo DayNightTimeStringField = AccessTools.Field(typeof(DayNightManager), "timeString");

		private static readonly HashSet<STATUSTYPE> SkippedSavedStatuses = new HashSet<STATUSTYPE> { (STATUSTYPE)7 };

		private static SaveManagerPlugin Instance;

		private static int? PendingSeedForLoad;

		private static float PendingSeedSetRealtime;

		private Harmony harmony;

		private ConfigEntry<bool> autoSaveEnabled;

		private ConfigEntry<float> autoSaveIntervalSeconds;

		private string saveDirectory;

		private string preferredSaveDirectory;

		private string fallbackSaveDirectory;

		private bool showUi;

		private bool isLoading;

		private float lastAutoSaveTime;

		private bool lastSceneLoadSucceeded = true;

		private Rect windowRect = new Rect(34f, 34f, 820f, 620f);

		private Vector2 fileScroll = Vector2.zero;

		private string newSaveName = "";

		private readonly List<SaveListEntry> saveEntries = new List<SaveListEntry>();

		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 const float SceneReadyTimeoutSeconds = 75f;

		private const int ScenePreparationLifetimeMs = 300000;

		private SharedScenePreparation sharedScenePreparation;

		private SceneLoadBarrier sceneLoadBarrier;

		private IEnumerator SyncLuggageClientsRoutine(string kind, string payload)
		{
			if (!PhotonNetwork.InRoom)
			{
				yield break;
			}
			if (!PhotonNetwork.IsMasterClient)
			{
				throw new InvalidOperationException("Only the host can restore luggage.");
			}
			List<string> requests = new List<string>();
			int expiresAt = PhotonNetwork.ServerTimestamp + 30000;
			float deadline = Time.realtimeSinceStartup + ((kind == "world-probe") ? 5f : 15f);
			try
			{
				Player[] playerListOthers = PhotonNetwork.PlayerListOthers;
				foreach (Player val in playerListOthers)
				{
					string text = Guid.NewGuid().ToString("N");
					ownerLoadReplies.Add(text, new OwnerLoadReply
					{
						actor = val.ActorNumber,
						viewId = 0
					});
					requests.Add(text);
					SendPlayerLoadEvent(val.ActorNumber, kind, text, 0, expiresAt, payload);
				}
				while (true)
				{
					bool flag = true;
					foreach (string item in requests)
					{
						OwnerLoadReply ownerLoadReply = ownerLoadReplies[item];
						if (!PhotonNetwork.InRoom || !PhotonNetwork.IsMasterClient || PhotonNetwork.CurrentRoom.GetPlayer(ownerLoadReply.actor, false) == null)
						{
							throw new InvalidOperationException("A player left or the host changed during luggage restoration.");
						}
						if (ownerLoadReply.completed && !string.IsNullOrEmpty(ownerLoadReply.error))
						{
							throw new InvalidOperationException("A client could not restore luggage: " + ownerLoadReply.error);
						}
						flag &= ownerLoadReply.completed;
					}
					if (!flag)
					{
						if (Time.realtimeSinceStartup >= deadline)
						{
							throw new TimeoutException((kind == "world-probe") ? "Every player in the room needs this save-manager version for luggage synchronization." : "A client did not confirm luggage restoration.");
						}
						yield return null;
						continue;
					}
					break;
				}
			}
			finally
			{
				SaveManagerPlugin saveManagerPlugin = this;
				foreach (string item2 in requests)
				{
					saveManagerPlugin.ownerLoadReplies.Remove(item2);
				}
			}
		}

		private void HandleLuggageRequest(string kind, string payload, int actor, string request, int expiresAt)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (kind == "world-probe")
				{
					ValidateLuggageApi();
					SendPlayerLoadEvent(actor, "reply", request, 0, expiresAt, "");
					return;
				}
				LuggageBatch luggageBatch = JsonConvert.DeserializeObject<LuggageBatch>(payload);
				if (luggageBatch?.states != null && luggageBatch.states.Count <= 1024 && luggageBatch.revision > 0)
				{
					string scene = luggageBatch.scene;
					Scene activeScene = SceneManager.GetActiveScene();
					if (!(scene != ((Scene)(ref activeScene)).name))
					{
						HashSet<int> hashSet = new HashSet<int>();
						foreach (LuggageRestoreState state in luggageBatch.states)
						{
							if (state == null || state.viewId <= 0 || !hashSet.Add(state.viewId) || !LuggageRestoration.IsFinite(state.position))
							{
								throw new InvalidOperationException("Invalid or duplicate luggage identity.");
							}
						}
						receivedLuggageRevisions.Receive(actor, luggageBatch.scene, luggageBatch.revision, luggageBatch.states);
						((MonoBehaviour)this).StartCoroutine(ReceiveLuggageRoutine(luggageBatch, actor, request, expiresAt));
						return;
					}
				}
				throw new InvalidOperationException("Luggage batch belongs to a different or unavailable scene.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Luggage synchronization failed: " + ex.Message));
				SendPlayerLoadEvent(actor, "reply", request, 0, expiresAt, ex.Message);
			}
		}

		private IEnumerator ReceiveLuggageRoutine(LuggageBatch batch, int actor, string request, int expiresAt)
		{
			float deadline = Time.realtimeSinceStartup + 10f;
			string error = null;
			List<Luggage> targets = new List<Luggage>();
			while (true)
			{
				try
				{
					if (!PhotonNetwork.InRoom)
					{
						goto IL_0098;
					}
					Player masterClient = PhotonNetwork.MasterClient;
					if (masterClient == null || masterClient.ActorNumber != actor || expiresAt - PhotonNetwork.ServerTimestamp <= 0)
					{
						goto IL_0098;
					}
					string scene = batch.scene;
					Scene activeScene = SceneManager.GetActiveScene();
					if (scene != ((Scene)(ref activeScene)).name)
					{
						goto IL_0098;
					}
					targets.Clear();
					foreach (LuggageRestoreState state in batch.states)
					{
						if (!receivedLuggageRevisions.IsCurrent(actor, batch.scene, batch.revision, state.viewId))
						{
							targets.Add(null);
							continue;
						}
						PhotonView val = PhotonView.Find(state.viewId);
						Luggage val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Luggage>() : null);
						if ((Object)(object)val2 == (Object)null)
						{
							break;
						}
						if (string.Equals(state.type, ((object)val2).GetType().FullName, StringComparison.Ordinal) && string.Equals(state.name, NormalizeObjectName(((Object)val2).name), StringComparison.Ordinal))
						{
							Vector3 val3 = ((Component)val2).transform.position - state.position.ToUnity();
							if (!(((Vector3)(ref val3)).sqrMagnitude > 400f))
							{
								targets.Add(val2);
								continue;
							}
						}
						throw new InvalidOperationException("A luggage network identity does not match the host.");
					}
					if (targets.Count == batch.states.Count)
					{
						ValidateLuggageApi();
						for (int i = 0; i < targets.Count; i++)
						{
							if ((Object)(object)targets[i] != (Object)null)
							{
								ApplyRestoredLuggage(targets[i], batch.states[i]);
							}
						}
						break;
					}
					if (Time.realtimeSinceStartup >= deadline)
					{
						throw new TimeoutException("Luggage network objects did not become ready.");
					}
					goto end_IL_0045;
					IL_0098:
					throw new InvalidOperationException("Luggage restoration expired or the host/scene changed.");
					end_IL_0045:;
				}
				catch (Exception ex)
				{
					error = ex.Message;
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Luggage synchronization failed: " + error));
					break;
				}
				yield return null;
			}
			if (PhotonNetwork.InRoom)
			{
				SendPlayerLoadEvent(actor, "reply", request, 0, expiresAt, error ?? "");
			}
		}

		private IEnumerator RestoreLuggageRoutine(List<ContainerSnapshot> containers, List<LuggageSnapshot> legacy, float readyDeadline)
		{
			List<LuggageRestoreState> snapshots = new List<LuggageRestoreState>();
			if (containers != null && containers.Count > 0)
			{
				foreach (ContainerSnapshot container in containers)
				{
					if (container != null && IsLuggageContainerSnapshot(container))
					{
						if (container.state < 0 || container.state > 1)
						{
							throw new InvalidOperationException("Invalid saved luggage state.");
						}
						snapshots.Add(new LuggageRestoreState
						{
							type = container.containerType,
							name = NormalizeObjectName(container.objectName),
							path = container.objectPath,
							position = container.position,
							open = (container.state == 1),
							activated = (container.activatedObjectActive ?? (container.state == 1)),
							spent = container.boolA,
							revivedPlayers = container.boolB
						});
					}
				}
			}
			else if (legacy != null)
			{
				foreach (LuggageSnapshot item in legacy)
				{
					if (item != null)
					{
						if (item.state < 0 || item.state > 1)
						{
							throw new InvalidOperationException("Invalid legacy luggage state.");
						}
						snapshots.Add(new LuggageRestoreState
						{
							type = (item.isRespawnChest ? typeof(RespawnChest).FullName : null),
							name = NormalizeObjectName(item.objectName),
							path = item.objectPath,
							position = item.position,
							open = (item.state == 1),
							activated = (item.activatedObjectActive ?? (item.state == 1)),
							spent = item.respawnChestSpent,
							revivedPlayers = item.respawnChestRevivedPlayers
						});
					}
				}
			}
			if (snapshots.Count == 0)
			{
				yield break;
			}
			if (snapshots.Count > 1024)
			{
				throw new InvalidOperationException("Too many saved luggage objects.");
			}
			ValidateLuggageApi();
			LuggageBatch luggageBatch = new LuggageBatch();
			Scene activeScene = SceneManager.GetActiveScene();
			luggageBatch.scene = ((Scene)(ref activeScene)).name;
			luggageBatch.revision = ++luggageRevision;
			LuggageBatch batch = luggageBatch;
			List<Luggage> targets = new List<Luggage>();
			List<Luggage> list;
			List<LuggageRestoreState> list2;
			int[] array;
			while (true)
			{
				string scene = batch.scene;
				activeScene = SceneManager.GetActiveScene();
				if (scene != ((Scene)(ref activeScene)).name || (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient))
				{
					throw new InvalidOperationException("The host or scene changed during luggage matching.");
				}
				list = (from x in Object.FindObjectsByType<Luggage>((FindObjectsSortMode)0)
					where (Object)(object)x != (Object)null
					select x).ToList();
				list2 = list.Select(CaptureLiveLuggage).ToList();
				array = LuggageRestoration.FindMatches(snapshots, list2, PhotonNetwork.InRoom);
				if (!array.Any((int index) => index < 0) || !(Time.realtimeSinceStartup < readyDeadline))
				{
					break;
				}
				yield return null;
			}
			targets.Clear();
			batch.states.Clear();
			for (int num = 0; num < snapshots.Count; num++)
			{
				LuggageRestoreState luggageRestoreState = snapshots[num];
				int num2 = array[num];
				if (num2 < 0)
				{
					string text = "Skipped saved luggage '" + (luggageRestoreState.name ?? "unnamed") + "' at " + $"({luggageRestoreState.position?.x}, {luggageRestoreState.position?.y}, {luggageRestoreState.position?.z}): " + "no unique nearby network object. The map may have changed; player restoration will continue.";
					if (worldRestoreWarnings.Add(text))
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)text);
					}
				}
				else
				{
					LuggageRestoreState luggageRestoreState2 = list2[num2];
					luggageRestoreState2.open = luggageRestoreState.open;
					luggageRestoreState2.activated = luggageRestoreState.activated;
					luggageRestoreState2.spent = luggageRestoreState.spent;
					luggageRestoreState2.revivedPlayers = luggageRestoreState.revivedPlayers;
					targets.Add(list[num2]);
					batch.states.Add(luggageRestoreState2);
				}
			}
			if (targets.Count == 0)
			{
				yield break;
			}
			restoredLuggage.RemoveWhere((Luggage x) => (Object)(object)x == (Object)null);
			for (int num3 = 0; num3 < targets.Count; num3++)
			{
				ApplyRestoredLuggage(targets[num3], batch.states[num3]);
			}
			IEnumerator sync = SyncLuggageClientsRoutine("luggage", JsonConvert.SerializeObject((object)batch));
			using (sync as IDisposable)
			{
				while (sync.MoveNext())
				{
					yield return sync.Current;
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"Restored {targets.Count} luggage states and confirmed all current clients.");
		}

		private static LuggageRestoreState CaptureLiveLuggage(Luggage luggage)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			PhotonView photonView = GetPhotonView((Component)(object)luggage);
			RespawnChest val = (RespawnChest)(object)((luggage is RespawnChest) ? luggage : null);
			return new LuggageRestoreState
			{
				viewId = (((Object)(object)photonView != (Object)null) ? photonView.ViewID : 0),
				type = ((object)luggage).GetType().FullName,
				name = NormalizeObjectName(((Object)luggage).name),
				path = BuildTransformPath(((Component)luggage).transform),
				position = new Vector3Snapshot(((Component)luggage).transform.position),
				open = (GetLuggageState(luggage) == 1),
				activated = ((Object)(object)luggage.activateOnOpen != (Object)null && luggage.activateOnOpen.activeSelf),
				spent = ((Object)(object)val != (Object)null && val.IsSpent),
				revivedPlayers = GetRespawnChestHasRevivedPlayers(val)
			};
		}

		private void ApplyRestoredLuggage(Luggage luggage, LuggageRestoreState state)
		{
			LuggageRestoration.Apply(new UnityLuggageRestoreTarget(luggage), state);
			restoredLuggage.Add(luggage);
		}

		private static void ValidateLuggageApi()
		{
			if (LuggageStateField == null || !LuggageStateField.FieldType.IsEnum || SpawnHistoryField == null || SpawnedItemsField == null || SetSpawnHistoryMethod == null)
			{
				throw new InvalidOperationException("The game's luggage restoration API changed.");
			}
		}

		private PlayerSnapshot ResolvePlayerLanding(Character character, PlayerSnapshot snapshot)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			if (!LandingSelection.NeedsSupport(snapshot?.character))
			{
				return snapshot;
			}
			if (snapshot.position == null || double.IsNaN(LandingSelection.DistanceSquared(snapshot.position, snapshot.position)))
			{
				throw new InvalidOperationException("Saved landing position is missing or nonfinite.");
			}
			if (ConditionalStandableField == null)
			{
				throw new InvalidOperationException("Native terrain standability API changed.");
			}
			Vector3 val = snapshot.position.ToUnity();
			int num = LayerMask.NameToLayer("Map");
			if (num < 0)
			{
				throw new InvalidOperationException("Cannot check saved landing: Map collision layer is missing.");
			}
			Physics.SyncTransforms();
			int num2 = 1 << num;
			float num3 = 0.3f;
			foreach (Bodypart part in character.refs.ragdoll.partList)
			{
				if ((Object)(object)part != (Object)null && (int)part.partType == 0)
				{
					num3 = Vector3.Distance(character.Center, part.transform.position);
				}
			}
			float num4 = Mathf.Clamp(character.data.targetHipHeight + num3, 0.9f, 1.4f);
			if (HasLandingSupport(character, val, num4, num2, preserveOriginal: true))
			{
				return snapshot;
			}
			List<Vector3Snapshot> list = new List<Vector3Snapshot>();
			for (float num5 = -8f; num5 <= 8f; num5 += 0.5f)
			{
				for (float num6 = -8f; num6 <= 8f; num6 += 0.5f)
				{
					if (num5 * num5 + num6 * num6 > 64f)
					{
						continue;
					}
					RaycastHit[] array = Physics.RaycastAll(val + new Vector3(num5, 10f, num6), Vector3.down, 20f, num2, (QueryTriggerInteraction)1);
					for (int i = 0; i < array.Length; i++)
					{
						RaycastHit hit = array[i];
						if (IsSafeLandingSurface(character, hit))
						{
							Vector3 val2 = ((RaycastHit)(ref hit)).point + Vector3.up * num4;
							Vector3Snapshot vector3Snapshot = new Vector3Snapshot(val2);
							if (LandingSelection.Closest(snapshot.position, new Vector3Snapshot[1] { vector3Snapshot }) != null && HasLandingSupport(character, val2, num4, num2, preserveOriginal: false))
							{
								list.Add(vector3Snapshot);
							}
						}
					}
				}
			}
			Vector3Snapshot vector3Snapshot2 = LandingSelection.Closest(snapshot.position, list);
			if (vector3Snapshot2 == null)
			{
				throw new InvalidOperationException("No stable landing within 8m horizontally / 8m vertically (10m total) of '" + snapshot.playerName + "'. Saved position is unsafe; player teleport cancelled.");
			}
			PlayerSnapshot playerSnapshot = JsonConvert.DeserializeObject<PlayerSnapshot>(JsonConvert.SerializeObject((object)snapshot));
			playerSnapshot.position = vector3Snapshot2;
			float num7 = Vector3.Distance(val, vector3Snapshot2.ToUnity());
			string text = $"{snapshot.playerName}: stable landing offset {num7:F1}m";
			landingRestoreWarnings.Add(text);
			ManualLogSource logger = ((BaseUnityPlugin)this).Logger;
			string[] obj = new string[6]
			{
				text,
				"; saved=",
				((Vector3)(ref val)).ToString("F3"),
				", landing=",
				null,
				null
			};
			Vector3 val3 = vector3Snapshot2.ToUnity();
			obj[4] = ((Vector3)(ref val3)).ToString("F3");
			obj[5] = ". Save file unchanged.";
			logger.LogWarning((object)string.Concat(obj));
			return playerSnapshot;
		}

		private static bool IsSafeLandingSurface(Character character, RaycastHit hit)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((RaycastHit)(ref hit)).collider == (Object)null || ((RaycastHit)(ref hit)).normal.y < 0.819152f || (Object)(object)((RaycastHit)(ref hit)).collider.attachedRigidbody != (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<Lava>() != (Object)null || (Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<LavaRiver>() != (Object)null || (Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<MovingLava>() != (Object)null || (Object)(object)((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent<KillPlane>() != (Object)null)
			{
				return false;
			}
			CollisionModifier component = ((Component)((RaycastHit)(ref hit)).collider).GetComponent<CollisionModifier>();
			if (!((Object)(object)component == (Object)null))
			{
				if (component.standable && !(bool)ConditionalStandableField.GetValue(component) && !component.applyEffects && !component.applyPetrify && component.knockback <= 0f)
				{
					return component.superBouncePow <= 0f;
				}
				return false;
			}
			return true;
		}

		private static bool HasLandingSupport(Character character, Vector3 torso, float torsoHeight, int mask, bool preserveOriginal)
		{
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			float num = float.PositiveInfinity;
			float num2 = float.NegativeInfinity;
			RaycastHit hit = default(RaycastHit);
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					if (!Physics.Raycast(torso + new Vector3((float)i * 0.3f, 0.35f, (float)j * 0.3f), Vector3.down, ref hit, torsoHeight + 0.65f, mask, (QueryTriggerInteraction)1) || !IsSafeLandingSurface(character, hit))
					{
						return false;
					}
					if (!LandingSelection.IsSupportSample(torso.y - ((RaycastHit)(ref hit)).point.y, torsoHeight, ((RaycastHit)(ref hit)).normal.y, preserveOriginal))
					{
						return false;
					}
					num = Mathf.Min(num, ((RaycastHit)(ref hit)).point.y);
					num2 = Mathf.Max(num2, ((RaycastHit)(ref hit)).point.y);
				}
			}
			if (num2 - num > 0.35f)
			{
				return false;
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(torso.x, num2 + 0.4f, torso.z);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(torso.x, Mathf.Max(torso.y + 0.35f, val.y), torso.z);
			Collider[] array = Physics.OverlapCapsule(val, val2, 0.3f, -1, (QueryTriggerInteraction)2);
			for (int k = 0; k < array.Length; k++)
			{
				if (!((Object)(object)((Component)array[k]).GetComponentInParent<Character>() == (Object)(object)character))
				{
					return false;
				}
			}
			return true;
		}

		private IEnumerator RestoreOnPlayerOwnerRoutine(Character character, PlayerSnapshot snapshot)
		{
			if (snapshot != null)
			{
				snapshot = ResolvePlayerLanding(character, snapshot);
			}
			PhotonView view = GetPhotonView((Component)(object)character);
			if ((Object)(object)view == (Object)null || view.IsMine)
			{
				if (snapshot == null)
				{
					yield break;
				}
				{
					IEnumerator local = PlayerLoadRestoration.Restore(new UnityPlayerLoadTarget(character, snapshot, () => !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient));
					try
					{
						while (local.MoveNext())
						{
							yield return local.Current;
						}
						yield break;
					}
					finally
					{
						IDisposable disposable = local as IDisposable;
						if (disposable != null)
						{
							disposable.Dispose();
						}
					}
				}
			}
			if (!PhotonNetwork.IsMasterClient || view.Owner == null)
			{
				throw new InvalidOperationException("Only the host can request restoration on a player's owner.");
			}
			string requestId = Guid.NewGuid().ToString("N");
			OwnerLoadReply reply = new OwnerLoadReply
			{
				actor = view.OwnerActorNr,
				viewId = view.ViewID
			};
			ownerLoadReplies.Add(requestId, reply);
			int expiresAt = PhotonNetwork.ServerTimestamp + 30000;
			try
			{
				SendPlayerLoadEvent(reply.actor, (snapshot == null) ? "probe" : "restore", requestId, reply.viewId, expiresAt, (snapshot == null) ? "" : JsonConvert.SerializeObject((object)snapshot));
				float deadline = Time.realtimeSinceStartup + ((snapshot == null) ? 5f : 30f);
				while (!reply.completed)
				{
					if ((Object)(object)character == (Object)null || (Object)(object)view == (Object)null || view.OwnerActorNr != reply.actor || !PhotonNetwork.IsMasterClient)
					{
						throw new InvalidOperationException("Player left or changed ownership during load.");
					}
					if (Time.realtimeSinceStartup >= deadline)
					{
						throw new TimeoutException((snapshot == null) ? "A restored player needs this save-manager build; owner support check timed out." : "Player owner did not confirm teleport/equipment restoration before timeout.");
					}
					yield return null;
				}
				if (!string.IsNullOrEmpty(reply.error))
				{
					throw new InvalidOperationException("Player owner could not restore the save: " + reply.error);
				}
			}
			finally
			{
				ownerLoadReplies.Remove(requestId);
			}
		}

		private static void SendPlayerLoadEvent(int actor, string kind, string requestId, int viewId, int expiresAt, string payload)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			object[] array = new object[7] { "com.lucasandersen.peakallyouneedsavemanager", 6, kind, requestId, viewId, expiresAt, payload };
			RaiseEventOptions val = new RaiseEventOptions();
			val.TargetActors = new int[1] { actor };
			if (!PhotonNetwork.RaiseEvent((byte)173, (object)array, val, SendOptions.SendReliable))
			{
				throw new InvalidOperationException("Could not send the player restoration request.");
			}
		}

		public void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 173 || !(photonEvent.CustomData is object[] array) || array.Length != 7 || !(array[0] is string text) || text != "com.lucasandersen.peakallyouneedsavemanager" || !(array[1] is int num) || num != 6 || !(array[2] is string text2) || !(array[3] is string text3) || !(array[4] is int num2) || !(array[5] is int num3) || !(array[6] is string text4))
			{
				return;
			}
			int num4;
			switch (text2)
			{
			case "scene-reply":
				if (num2 == 0 && num3 - PhotonNetwork.ServerTimestamp > 0)
				{
					sceneLoadBarrier?.Acknowledge(photonEvent.Sender, text3, text4);
				}
				return;
			case "reply":
			{
				if (ownerLoadReplies.TryGetValue(text3, out var value) && value.actor == photonEvent.Sender && value.viewId == num2)
				{
					value.error = text4;
					value.completed = true;
				}
				return;
			}
			default:
				num4 = ((text2 == "scene-finish") ? 1 : 0);
				break;
			case "scene-check":
			case "scene-prepare":
			case "scene-arm":
			case "scene-ready":
			case "scene-cancel":
				num4 = 1;
				break;
			}
			bool flag = (byte)num4 != 0;
			bool flag2 = text2 == "scene-cancel" || text2 == "scene-finish";
			if ((!flag && text2 != "probe" && text2 != "restore" && text2 != "world-probe" && text2 != "luggage") || PhotonNetwork.MasterClient == null || photonEvent.Sender != PhotonNetwork.MasterClient.ActorNumber || (!flag2 && num3 - PhotonNetwork.ServerTimestamp <= 0))
			{
				return;
			}
			if (flag)
			{
				if (num2 == 0)
				{
					HandleSharedSceneRequest(text2, text4, photonEvent.Sender, text3, num3);
				}
				return;
			}
			if (text2 == "world-probe" || text2 == "luggage")
			{
				if (num2 == 0)
				{
					HandleLuggageRequest(text2, text4, photonEvent.Sender, text3, num3);
				}
				return;
			}
			try
			{
				PhotonView val = PhotonView.Find(num2);
				Character val2 = (((Object)(object)val != (Object)null && val.IsMine) ? ((Component)val).GetComponent<Character>() : null);
				if ((Object)(object)val2 == (Object)null || !val2.IsLocal)
				{
					throw new InvalidOperationException("Requested player is not owned by this client.");
				}
				if (text2 == "probe")
				{
					SendPlayerLoadEvent(photonEvent.Sender, "reply", text3, num2, num3, "");
					return;
				}
				PlayerSnapshot playerSnapshot = JsonConvert.DeserializeObject<PlayerSnapshot>(text4);
				if (playerSnapshot?.position == null || playerSnapshot.rotation == null || playerSnapshot.character?.lookValues == null)
				{
					throw new InvalidOperationException("Player position or view snapshot is missing.");
				}
				if (!ownerLoadsInProgress.Add(num2))
				{
					throw new InvalidOperationException("A restoration is already running for this player.");
				}
				((MonoBehaviour)this).StartCoroutine(RestoreRequestedPlayerRoutine(val2, playerSnapshot, photonEvent.Sender, text3, num2, num3));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Owner restoration request failed: " + ex.Message));
				SendPlayerLoadEvent(photonEvent.Sender, "reply", text3, num2, num3, ex.Message);
			}
		}

		private IEnumerator RestoreRequestedPlayerRoutine(Character character, PlayerSnapshot snapshot, int requester, string requestId, int viewId, int expiresAt)
		{
			string error = "";
			IEnumerator routine = PlayerLoadRestoration.Restore(new UnityPlayerLoadTarget(character, snapshot, () => PhotonNetwork.MasterClient != null && PhotonNetwork.MasterClient.ActorNumber == requester && expiresAt - PhotonNetwork.ServerTimestamp > 0));
			try
			{
				while (true)
				{
					object current;
					try
					{
						if (!routine.MoveNext())
						{
							break;
						}
						current = routine.Current;
						goto IL_00e5;
					}
					catch (Exception ex)
					{
						error = ex.Message;
						((BaseUnityPlugin)this).Logger.LogError((object)("Owner player restoration failed: " + ex));
					}
					break;
					IL_00e5:
					yield return current;
				}
			}
			finally
			{
				SaveManagerPlugin saveManagerPlugin = this;
				(routine as IDisposable)?.Dispose();
				saveManagerPlugin.ownerLoadsInProgress.Remove(viewId);
			}
			if (PhotonNetwork.InRoom)
			{
				SendPlayerLoadEvent(requester, "reply", requestId, viewId, expiresAt, error);
			}
		}

		private void Awake()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_00b7: 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");
			preferredSaveDirectory = Path.Combine(Paths.GameRootPath, "PeakSaves");
			fallbackSaveDirectory = Path.Combine(Application.persistentDataPath, "PeakSaves");
			saveDirectory = preferredSaveDirectory;
			EnsureSaveDirectoryReady(showStatus: false);
			harmony = new Harmony("com.lucasandersen.peakallyouneedsavemanager");
			harmony.PatchAll();
			PhotonNetwork.AddCallbackTarget((object)this);
			RefreshSaveFileList();
			SetStatus("Save manager ready.", Color.cyan, 2f);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loaded The All You Need Save Manager Continued 1.2.5; original mod by Lucas Andersen.");
		}

		private void OnDestroy()
		{
			EndSharedScenePreparation(succeeded: false);
			PhotonNetwork.RemoveCallbackTarget((object)this);
			try
			{
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)$"Failed to unpatch Harmony cleanly: {arg}");
			}
			DestroyUiResources();
		}

		private void Update()
		{
			UpdateSharedScenePreparation();
			if (showUi)
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
			if (!showUi && !isLoading && sharedScenePreparation == null && 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)
		{
			GUIStyle obj = (entry.isCompatible ? cardStyle : cardWarningStyle);
			bool flag = CanSaveNow(showReason: false);
			GUILayout.BeginVertical(obj, 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 && flag;
			if (GUILayout.Button("Overwrite", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(24f),
				GUILayout.Width(100f)
			}))
			{
				string saveNameHint = ((entry.metadata != null && !string.IsNullOrWhiteSpace(entry.metadata.saveName)) ? entry.metadata.saveName : Path.GetFileNameWithoutExtension(entry.fileName));
				string targetPath = entry.fullPath;
				string fileName = entry.fileName;
				RequestConfirmation("Overwrite Save?", "Overwrite '" + fileName + "' with your current run state?", delegate
				{
					TryOverwriteSave(targetPath, saveNameHint);
				});
			}
			GUI.enabled = !isLoading;
			if (GUILayout.Button("Delete", dangerButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(24f),
				GUILayout.Width(90f)
			}))
			{
				string targetPath2 = entry.fullPath;
				string fileName2 = entry.fileName;
				RequestConfirmation("Delete Save?", "Delete '" + fileName2 + "' permanently? This cannot be undone.", delegate
				{
					TryDeleteSave(targetPath2);
				});
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		private void StartLoadFromUi(string fullPath)
		{
			if (!string.IsNullOrWhiteSpace(fullPath))
			{
				showUi = false;
				ClearPendingConfirmation();
				pauseMenuPage?.PrepareForLoad();
				ClosePauseMenuForLoad();
				((MonoBehaviour)this).StartCoroutine(LoadSaveRoutine(fullPath));
			}
		}

		private void ClosePauseMenuForLoad()
		{
			try
			{
				if ((Object)(object)EventSystem.current != (Object)null)
				{
					EventSystem.current.SetSelectedGameObject((GameObject)null);
				}
				PauseMainMenu val = Object.FindFirstObjectByType<PauseMainMenu>();
				if ((Object)(object)val != (Object)null)
				{
					CloseMenuWindow((MenuWindow)(object)val);
					((Component)val).gameObject.SetActive(false);
				}
				if ((Object)(object)pauseMenuPage != (Object)null)
				{
					((Component)pauseMenuPage).gameObject.SetActive(false);
				}
				if ((Object)(object)pauseMenuPageHandler != (Object)null)
				{
					((Component)pauseMenuPageHandler).gameObject.SetActive(false);
				}
				Cursor.visible = false;
				Cursor.lockState = (CursorLockMode)1;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to close pause menu before load: " + ex.Message));
			}
		}

		private void ToggleUi()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				SetStatus("Only the host can open Save Manager.", Color.yellow, 2.5f);
				return;
			}
			showUi = !showUi;
			if (showUi)
			{
				RefreshSaveFileList();
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
			else
			{
				ClearPendingConfirmation();
			}
		}

		private void RequestConfirmation(string title, string message, Action confirmedAction)
		{
			if (confirmedAction != null)
			{
				hasConfirmationPending = true;
				confirmationTitle = (string.IsNullOrWhiteSpace(title) ? "Are you sure?" : title);
				confirmationMessage = (string.IsNullOrWhiteSpace(message) ? "Please confirm this action." : message);
				confirmationAction = confirmedAction;
			}
		}

		private void ClearPendingConfirmation()
		{
			hasConfirmationPending = false;
			confirmationTitle = string.Empty;
			confirmationMessage = string.Empty;
			confirmationAction = null;
		}

		private void ExecutePendingConfirmation()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Action action = confirmationAction;
			ClearPendingConfirmation();
			if (action == null)
			{
				return;
			}
			try
			{
				action();
			}
			catch (Exception arg)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Confirmation action failed: {arg}");
				SetStatus("Action failed. Check BepInEx log.", Color.red, 4f);
			}
		}

		private void DrawConfirmationPrompt()
		{
			GUILayout.Space(8f);
			GUILayout.BeginVertical(sectionStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Label(confirmationTitle, subtitleStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.Label(confirmationMessage, normalLabelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Space(10f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			GUI.enabled = !isLoading;
			if (GUILayout.Button("Cancel", softButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(30f),
				GUILayout.Width(120f)
			}))
			{
				ClearPendingConfirmation();
			}
			GUI.enabled = !isLoading;
			if (GUILayout.Button("Confirm", dangerButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(30f),
				GUILayout.Width(120f)
			}))
			{
				ExecutePendingConfirmation();
			}
			GUI.enabled = true;
			GUILayout.EndHorizontal();
			GUILayout.EndVertical();
		}

		internal static void TryAttachPauseMenuButton(PauseMenuMainPage pauseMenuPage)
		{
			Instance?.AttachPauseMenuButton(pauseMenuPage);
		}

		private void AttachPauseMenuButton(PauseMenuMainPage pauseMenuPage)
		{
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)pauseMenuPage == (Object)null)
			{
				return;
			}
			try
			{
				object? obj = AccessTools.Field(typeof(PauseMenuMainPage), "m_settingsButton")?.GetValue(pauseMenuPage);
				Button val = (Button)((obj is Button) ? obj : null);
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null || (Object)(object)((Component)val).transform.parent == (Object)null)
				{
					return;
				}
				Transform parent = ((Component)val).transform.parent;
				Transform val2 = parent.Find("PeakSaveManagerButton");
				Button component;
				if ((Object)(object)val2 == (Object)null)
				{
					GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false);
					((Object)val3).name = "PeakSaveManagerButton";
					Transform transform = ((Component)val).transform;
					RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
					Transform transform2 = val3.transform;
					RectTransform val5 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
					if ((Object)(object)val4 != (Object)null && (Object)(object)val5 != (Object)null)
					{
						val5.anchorMin = val4.anchorMin;
						val5.anchorMax = val4.anchorMax;
						val5.pivot = val4.pivot;
						val5.sizeDelta = val4.sizeDelta;
						((Transform)val5).localScale = ((Transform)val4).localScale;
						Vector2 anchoredPosition = val4.anchoredPosition;
						Rect rect = val4.rect;
						val5.anchoredPosition = anchoredPosition + new Vector2(0f, 0f - Mathf.Max(50f, ((Rect)(ref rect)).height + 8f));
					}
					val3.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
					MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren<MonoBehaviour>(true);
					foreach (MonoBehaviour val6 in componentsInChildren)
					{
						if ((Object)(object)val6 != (Object)null && ((object)val6).GetType().Name == "LocalizedText")
						{
							Object.Destroy((Object)(object)val6);
						}
					}
					SetPauseMenuButtonText(val3, "SAVE MANAGER");
					component = val3.GetComponent<Button>();
				}
				else
				{
					component = ((Component)val2).GetComponent<Button>();
				}
				if (!((Object)(object)component == (Object)null))
				{
					((UnityEventBase)component.onClick).RemoveAllListeners();
					((UnityEvent)component.onClick).AddListener((UnityAction)delegate
					{
						OpenPauseMenuSavePage(pauseMenuPage);
					});
					((Selectable)component).interactable = !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Failed to attach pause menu save button: " + ex.Message));
			}
		}

		private void OpenPauseMenuSavePage(PauseMenuMainPage pauseMainPage)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			if ((Object)(object)pauseMainPage == (Object)null)
			{
				return;
			}
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				SetStatus("Only the host can open Save Manager.", Color.yellow, 2.5f);
				return;
			}
			UIPageHandler pageHandler = ((UIPage)pauseMainPage).GetPageHandler<UIPageHandler>();
			if ((Object)(object)pageHandler == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Pause menu page handler not found.");
				return;
			}
			object? obj = AccessTools.Field(typeof(PauseMenuMainPage), "m_settingsButton")?.GetValue(pauseMainPage);
			Button settingsButtonTemplate = (Button)((obj is Button) ? obj : null);
			SaveManagerPausePage saveManagerPausePage = EnsurePauseMenuSavePage(pageHandler, (UIPage)(object)pauseMainPage, settingsButtonTemplate);
			if ((Object)(object)saveManagerPausePage == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Save manager pause page could not be created.");
				return;
			}
			saveManagerPausePage.RefreshFromSource();
			pageHandler.TransistionToPage((UIPage)(object)saveManagerPausePage, (PageTransistion)new SetActivePageTransistion());
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
		}

		private SaveManagerPausePage EnsurePauseMenuSavePage(UIPageHandler pageHandler, UIPage mainPage, Button settingsButtonTemplate)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)pageHandler == (Object)null || (Object)(object)mainPage == (Object)null)
			{
				return null;
			}
			if ((Object)(object)pauseMenuPage != (Object)null && (Object)(object)pauseMenuPageHandler == (Object)(object)pageHandler)
			{
				pauseMenuPage.Initialize(this, pageHandler, mainPage, settingsButtonTemplate);
				return pauseMenuPage;
			}
			SaveManagerPausePage saveManagerPausePage = pageHandler.GetPage<SaveManagerPausePage>() as SaveManagerPausePage;
			if ((Object)(object)saveManagerPausePage != (Object)null)
			{
				pauseMenuPage = saveManagerPausePage;
				pauseMenuPageHandler = pageHandler;
				pauseMenuMainPage = mainPage;
				pauseMenuButtonTemplate = settingsButtonTemplate;
				pauseMenuPage.Initialize(this, pageHandler, mainPage, settingsButtonTemplate);
				return pauseMenuPage;
			}
			GameObject val = new GameObject("PauseMenuSaveManagerPage", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(SaveManagerPausePage)
			});
			RectTransform component = val.GetComponent<RectTransform>();
			((Transform)component).SetParent(((Component)pageHandler).transform, false);
			component.anchorMin = Vector2.zero;
			component.anchorMax = Vector2.one;
			component.offsetMin = Vector2.zero;
			component.offsetMax = Vector2.zero;
			((Graphic)val.GetComponent<Image>()).color = new Color(0.02f, 0.05f, 0.1f, 0.75f);
			SaveManagerPausePage component2 = val.GetComponent<SaveManagerPausePage>();
			AccessTools.Field(typeof(UIPage), "pageHandler")?.SetValue(component2, pageHandler);
			component2.Initialize(this, pageHandler, mainPage, settingsButtonTemplate);
			val.SetActive(false);
			object obj = AccessTools.Field(typeof(UIPageHandler), "_pages")?.GetValue(pageHandler);
			if (obj != null)
			{
				obj.GetType().GetMethod("Remove", new Type[1] { typeof(Type) })?.Invoke(obj, new object[1] { typeof(SaveManagerPausePage) });
				MethodInfo method = obj.GetType().GetMethod("Add", new Type[2]
				{
					typeof(Type),
					typeof(UIPage)
				});
				if (method != null)
				{
					method.Invoke(obj, new object[2]
					{
						typeof(SaveManagerPausePage),
						component2
					});
				}
				else
				{
					obj.GetType().GetMethod("Add")?.Invoke(obj, new object[2]
					{
						typeof(SaveManagerPausePage),
						component2
					});
				}
			}
			pauseMenuPage = component2;
			pauseMenuPageHandler = pageHandler;
			pauseMenuMainPage = mainPage;
			pauseMenuButtonTemplate = settingsButtonTemplate;
			return component2;
		}

		internal static bool TryInterceptPauseQuit(PauseMenuMainPage page)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				return Instance.InterceptPauseQuit(page);
			}
			return false;
		}

		private bool InterceptPauseQuit(PauseMenuMainPage page)
		{
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Expected O, but got Unknown
			if (allowVanillaQuitClick || (Object)(object)page == (Object)null)
			{
				return false;
			}
			if (!CanSaveNow(showReason: false))
			{
				return false;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(PauseMenuMainPage), "confirmWindow");
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(PauseMenuMainPage), "m_confirmOkButton");
			FieldInfo fieldInfo3 = AccessTools.Field(typeof(PauseMenuMainPage), "m_confirmCancelButton");
			FieldInfo fieldInfo4 = AccessTools.Field(typeof(PauseMenuMainPage), "confirmText");
			MenuWindow confirmWindow = default(MenuWindow);
			ref MenuWindow reference = ref confirmWindow;
			object? obj = fieldInfo?.GetValue(page);
			reference = (MenuWindow)((obj is MenuWindow) ? obj : null);
			object? obj2 = fieldInfo2?.GetValue(page);
			Button val = (Button)((obj2 is Button) ? obj2 : null);
			object? obj3 = fieldInfo3?.GetValue(page);
			Button val2 = (Button)((obj3 is Button) ? obj3 : null);
			object? obj4 = fieldInfo4?.GetValue(page);
			LocalizedText val3 = (LocalizedText)((obj4 is LocalizedText) ? obj4 : null);
			if ((Object)(object)confirmWindow == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return false;
			}
			quitPendingSaveDecision = true;
			quitPendingPage = page;
			OpenMenuWindow(confirmWindow);
			if (val3 != null)
			{
				val3.SetText("Would you like to save your game before quitting?");
			}
			SetPauseMenuButtonText(((Component)val).gameObject, "YES");
			SetPauseMenuButtonText(((Component)val2).gameObject, "NO");
			((UnityEventBase)val.onClick).RemoveAllListeners();
			((UnityEvent)val.onClick).AddListener((UnityAction)delegate
			{
				CloseMenuWindow(confirmWindow);
				OpenPauseMenuSavePage(page);
			});
			((UnityEventBase)val2.onClick).RemoveAllListeners();
			((UnityEvent)val2.onClick).AddListener((UnityAction)delegate
			{
				CloseMenuWindow(confirmWindow);
				quitPendingSaveDecision = false;
				quitPendingPage = null;
				ContinueWithVanillaQuit(page);
			});
			return true;
		}

		private void ContinueWithVanillaQuit(PauseMenuMainPage page)
		{
			if ((Object)(object)page == (Object)null)
			{
				return;
			}
			try
			{
				allowVanillaQuitClick = true;
				MethodInfo methodInfo = AccessTools.Method(typeof(PauseMenuMainPage), "Quit", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(page, null);
				}
				else
				{
					AccessTools.Method(typeof(PauseMenuMainPage), "OnQuitClicked", (Type[])null, (Type[])null)?.Invoke(page, null);
				}
			}
			finally
			{
				allowVanillaQuitClick = false;
			}
		}

		private static void SetPauseMenuButtonText(GameObject buttonObject, string text)
		{
			if ((Object)(object)buttonObject == (Object)null)
			{
				return;
			}
			TMP_Text componentInChildren = buttonObject.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				componentInChildren.enableAutoSizing = true;
				componentInChildren.fontSizeMin = 13f;
				componentInChildren.fontSizeMax = 21f;
				componentInChildren.fontStyle = (FontStyles)16;
				componentInChildren.overflowMode = (TextOverflowModes)1;
				return;
			}
			Text componentInChildren2 = buttonObject.GetComponentInChildren<Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.text = text;
				componentInChildren2.fontStyle = (FontStyle)0;
				componentInChildren2.resizeTextForBestFit = true;
				componentInChildren2.resizeTextMinSize = 13;
				componentInChildren2.resizeTextMaxSize = 21;
			}
		}

		private static void OpenMenuWindow(MenuWindow window)
		{
			if ((Object)(object)window == (Object)null)
			{
				return;
			}
			try
			{
				MenuWindowOpenMethod?.Invoke(window, null);
			}
			catch
			{
				((Component)window).gameObject.SetActive(true);
			}
		}

		private static void CloseMenuWindow(MenuWindow window)
		{
			if ((Object)(object)window == (Object)null)
			{
				return;
			}
			try
			{
				MenuWindowCloseMethod?.Invoke(window, null);
			}
			catch
			{
				((Component)window).gameObject.SetActive(false);
			}
		}

		private static int GetLuggageState(Luggage luggage)
		{
			if ((Object)(object)luggage == (Object)null || LuggageStateField == null)
			{
				return 0;
			}
			try
			{
				object value = LuggageStateField.GetValue(luggage);
				return (value != null) ? Convert.ToInt32(value, CultureInfo.InvariantCulture) : 0;
			}
			catch
			{
				return 0;
			}
		}

		private static PhotonView GetPhotonView(Component component)
		{
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			PhotonView component2 = component.GetComponent<PhotonView>();
			if ((Object)(object)component2 != (Object)null)
			{
				return component2;
			}
			return component.GetComponentInParent<PhotonView>();
		}

		private static void SetRespawnChestState(RespawnChest respawnChest, bool isSpent, bool hasRevivedPlayers)
		{
			if ((Object)(object)respawnChest == (Object)null)
			{
				return;
			}
			try
			{
				RespawnChestSetSpentMethod?.Invoke(respawnChest, new object[1] { isSpent });
				SetRespawnChestHasRevivedPlayers(respawnChest, hasRevivedPlayers);
			}
			catch
			{
			}
		}

		private static bool GetRespawnChestHasRevivedPlayers(RespawnChest respawnChest)
		{
			if ((Object)(object)respawnChest == (Object)null)
			{
				return false;
			}
			try
			{
				if (RespawnChestGetRevivedPlayersMethod?.Invoke(respawnChest, null) is bool result)
				{
					return result;
				}
				if (RespawnChestRevivedPlayersField?.GetValue(respawnChest) is bool result2)
				{
					return result2;
				}
			}
			catch
			{
			}
			if ((Object)(object)respawnChest.skeleton != (Object)null)
			{
				return !respawnChest.skeleton.activeSelf;
			}
			return false;
		}

		private static void SetRespawnChestHasRevivedPlayers(RespawnChest respawnChest, bool hasRevivedPlayers)
		{
			if ((Object)(object)respawnChest == (Object)null)
			{
				return;
			}
			try
			{
				if (RespawnChestSetRevivedPlayersMethod != null)
				{
					RespawnChestSetRevivedPlayersMethod.Invoke(respawnChest, new object[1] { hasRevivedPlayers });
				}
				else
				{
					RespawnChestRevivedPlayersField?.SetValue(respawnChest, hasRevivedPlayers);
				}
			}
			catch
			{
			}
		}

		private static string GetDayNightTimeString(DayNightManager dayNight)
		{
			if ((Object)(object)dayNight == (Object)null)
			{
				return string.Empty;
			}
			try
			{
				if ((DayNightTimeStringGetterMethod?.Invoke(dayNight, null) ?? DayNightTimeStringField?.GetValue(dayNight)) is string result)
				{
					return result;
				}
			}
			catch
			{
			}
			return string.Empty;
		}

		private static void SetDayNightTimeString(DayNightManager dayNight, string timeString)
		{
			if ((Object)(object)dayNight == (Object)null || string.IsNullOrWhiteSpace(timeString))
			{
				return;
			}
			try
			{
				if (DayNightTimeStringSetterMethod != null)
				{
					DayNightTimeStringSetterMethod.Invoke(dayNight, new object[1] { timeString });
				}
				else
				{
					DayNightTimeStringField?.SetValue(dayNight, timeString);
				}
			}
			catch
			{
			}
		}

		private bool CanSaveNow(bool showReason)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (IsInAirportScene())
			{
				if (showReason)
				{
					SetStatus("You cannot save in the Airport.", Color.yellow, 3f);
				}
				return false;
			}
			if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
			{
				if (showReason)
				{
					SetStatus("Only host can save shared runs.", Color.yellow, 3f);
				}
				return false;
			}
			return true;
		}

		private bool TrySaveGame(string saveName)
		{
			//IL_00f7: 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)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			if (!CanSaveNow(showReason: true))
			{
				return false;
			}
			try
			{
				if (!EnsureSaveDirectoryReady(showStatus: true))
				{
					return false;
				}
				string text = NormalizeSaveDisplayName(saveName);
				SaveEnvelope saveEnvelope = CaptureSnapshot(text);
				if (saveEnvelope.players == null || saveEnvelope.players.Count == 0)
				{
					SetStatus("Could not find an active player to save. Try again in-run.", Color.yellow, 4f);
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Save aborted: snapshot captured 0 players.");
					return false;
				}
				string text2 = ResolveSavePathForName(text);
				string contents = JsonConvert.SerializeObject((object)saveEnvelope, (Formatting)1);
				File.WriteAllText(text2, contents);
				if (text.Equals("Autosave", StringComparison.OrdinalIgnoreCase))
				{
					CleanupLegacyAutosaves(text2);
				}
				RefreshSaveFileList();
				SetStatus("Saved: " + text, Color.green, 3f);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Saved run to " + text2));
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Save failed: {ex}");
				SetStatus(BuildSaveFailureStatus(ex), Color.red, 6f);
				return false;
			}
		}

		private bool TryOverwriteSave(string fullPath, string saveNameHint)
		{
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			if (!CanSaveNow(showReason: true))
			{
				return false;
			}
			if (string.IsNullOrWhiteSpace(fullPath))
			{
				SetStatus("Invalid save path.", Color.red, 4f);
				return false;
			}
			try
			{
				if (!EnsureSaveDirectoryReady(showStatus: true))
				{
					return false;
				}
				string text = NormalizeSaveDisplayName(string.IsNullOrWhiteSpace(saveNameHint) ? Path.GetFileNameWithoutExtension(fullPath) : saveNameHint.Trim());
				SaveEnvelope saveEnvelope = CaptureSnapshot(text);
				if (saveEnvelope.players == null || saveEnvelope.players.Count == 0)
				{
					SetStatus("Could not find an active player to overwrite from. Try again in-run.", Color.yellow, 4f);
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Overwrite aborted for '" + fullPath + "': snapshot captured 0 players."));
					return false;
				}
				string contents = JsonConvert.SerializeObject((object)saveEnvelope, (Formatting)1);
				File.WriteAllText(fullPath, contents);
				RefreshSaveFileList();
				SetStatus("Overwrote save: " + text, Color.green, 3f);
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Overwrote run at " + fullPath));
				return true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)$"Overwrite failed for '{fullPath}': {ex}");
				SetStatus(BuildSaveFailureStatus(ex), Color.red, 6f);
				return false;
			}
		}

		internal void UiRefreshSaveList()
		{
			RefreshSaveFileList();
		}

		internal List<SaveListEntry> UiGetSaveEntries()
		{
			return new List<SaveListEntry>(saveEntries);
		}

		internal void UiQuickSave()
		{
			bool saveSucceeded = TrySaveGame("Quick Save");
			MaybeCompletePendingQuitAfterSave(saveSucceeded);
		}

		internal void UiNamedSave(string saveName)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(saveName))
			{
				SetStatus("Enter a save name first.", Color.yellow, 3f);
				return;
			}
			bool saveSucceeded = TrySaveGame(saveName.Trim());
			MaybeCompletePendingQuitAfterSave(saveSucceeded);
		}

		internal void UiLoadSave(string fullPath)
		{
			StartLoadFromUi(fullPath);
		}

		internal void UiOverwriteSave(string fullPath, string saveNameHint)
		{
			bool saveSucceeded = TryOverwriteSave(fullPath, saveNameHint);
			MaybeCompletePendingQuitAfterSave(saveSucceeded);
		}

		internal void UiDeleteSave(string fullPath)
		{
			TryDeleteSave(fullPath);
		}

		internal bool UiCanSaveNow(bool showReason = false)
		{
			return CanSaveNow(showReason);
		}

		internal bool UiIsLoading()
		{
			return isLoading;
		}

		internal string UiCurrentStatus()
		{
			if (string.IsNullOrWhiteSpace(statusMessage))
			{
				return string.Empty;
			}
			if (statusMessageUntil <= Time.unscaledTime)
			{
				return string.Empty;
			}
			return statusMessage;
		}

		internal bool UiHasPendingQuitSaveDecision()
		{
			return quitPendingSaveDecision;
		}

		internal void UiQuickSaveAndQuit()
		{
			if (CanSaveNow(showReason: true) && TrySaveGame("Quick Save"))
			{
				CompletePendingQuit();
			}
		}

		internal void UiNamedSaveAndQuit(string saveName)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (CanSaveNow(showReason: true))
			{
				if (string.IsNullOrWhiteSpace(saveName))
				{
					SetStatus("Enter a save name before Save & Quit.", Color.yellow, 3f);
				}
				else if (TrySaveGame(saveName.Trim()))
				{
					CompletePendingQuit();
				}
			}
		}

		internal void UiQuitWithoutSaving()
		{
			CompletePendingQuit();
		}

		internal void UiCancelPendingQuit()
		{
			quitPendingSaveDecision = false;
			quitPendingPage = null;
		}

		private void MaybeCompletePendingQuitAfterSave(bool saveSucceeded)
		{
			if (saveSucceeded && quitPendingSaveDecision)
			{
				CompletePendingQuit();
			}
		}

		private void CompletePendingQuit()
		{
			PauseMenuMainPage page = quitPendingPage;
			quitPendingSaveDecision = false;
			quitPendingPage = null;
			ContinueWithVanillaQuit(page);
		}

		private unsafe SaveEnvelope CaptureSnapshot(string saveName)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected I4, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			LevelGeneration val = Object.FindFirstObjectByType<LevelGeneration>();
			int levelSeed = (((Object)(object)val != (Object)null) ? val.seed : 0);
			int num = 0;
			string currentSegmentName = ((object)(Segment)0/*cast due to .constrained prefix*/).ToString();
			string currentBiomeName = null;
			if (MapHandler.Exists)
			{
				MapHandler val2 = Object.FindFirstObjectByType<MapHandler>();
				if ((Object)(object)val2 != (Object)null)
				{
					Segment currentSegment = val2.GetCurrentSegment();
					num = (int)currentSegment;
					currentSegmentName = ((object)(*(Segment*)(&currentSegment))/*cast due to .constrained prefix*/).ToString();
					if (val2.segments != null && num >= 0 && num < val2.segments.Length)
					{
						currentBiomeName = ((object)MapHandler.GetBiomeForSegment(num)/*cast due to .constrained prefix*/).ToString();
					}
				}
			}
			int? dailyLevelIndex = null;
			string biomeId = string.Empty;
			try
			{
				NextLevelService service = GameHandler.GetService<NextLevelService>();
				if (service != null && service.HasReceivedLevelIndex)
				{
					dailyLevelIndex = service.NextLevelIndexOrFallback;
					biomeId = SingletonAsset<MapBaker>.Instance.GetBiomeID(dailyLevelIndex.Value + NextLevelService.debugLevelIndexOffset);
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not capture NextLevelService metadata: " + ex.Message));
			}
			string text = ResolveLevelName(name, dailyLevelIndex);
			int? levelNumber = ParseLevelNumber(text);
			CaptureRunMetadata(out var runDay, out var runTimeSeconds, out var runTimerActive, out var timeOfDay, out var inGameTime);
			SaveEnvelope saveEnvelope = new SaveEnvelope
			{
				pluginGuid = "com.lucasandersen.peakallyouneedsavemanager",
				pluginVersion = "1.2.5",
				me