Decompiled source of PEAK Save Manager v1.0.1

BepInEx/plugins/PEAKSaveManager.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Newtonsoft.Json;
using PEAKSaveManager.Patches;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core.Serizalization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PEAKSaveManager")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PEAKSaveManager")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("06cb7bdd-b341-45d6-bfcf-dabd9498a75c")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PEAKSaveManager
{
	[BepInPlugin("com.maxbridgland.peaksavemanager", "PEAK Save Manager", "1.0.1")]
	public class SaveManagerMod : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <ApplyLoadedDataCoroutine>d__44 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public GameSaveData saveData;

			public SaveManagerMod <>4__this;

			public string fileName;

			private int <successCount>5__2;

			private int <totalPlayers>5__3;

			private List<PlayerSaveData>.Enumerator <>7__wrap3;

			private PlayerSaveData <playerData>5__5;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ApplyLoadedDataCoroutine>d__44(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || (uint)(num - 2) <= 1u)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<>7__wrap3 = default(List<PlayerSaveData>.Enumerator);
				<playerData>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_026a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0274: Expected O, but got Unknown
				//IL_0135: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Expected O, but got Unknown
				//IL_0111: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					int num = <>1__state;
					SaveManagerMod saveManagerMod = <>4__this;
					switch (num)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						Logger.LogInfo((object)$"Loading save data with {saveData.players.Count} players");
						saveManagerMod.ShowStatusMessage("Loading: " + fileName + "...", 5f);
						if ((Object)(object)Object.FindFirstObjectByType<MapHandler>() != (Object)null)
						{
							MethodInfo methodInfo = AccessTools.Method(typeof(MapHandler), "JumpToSegmentLogic", new Type[3]
							{
								typeof(Segment),
								typeof(HashSet<int>),
								typeof(bool)
							}, (Type[])null);
							HashSet<int> hashSet = (from player in PlayerHandler.GetAllPlayers()
								select ((MonoBehaviourPun)player).photonView.Owner.ActorNumber).ToHashSet();
							methodInfo.Invoke(null, new object[3]
							{
								saveManagerMod.StringToSegment(saveData.mapSegment),
								hashSet,
								true
							});
						}
						<>2__current = (object)new WaitForSeconds(1f);
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						<successCount>5__2 = 0;
						<totalPlayers>5__3 = saveData.players.Count;
						<>7__wrap3 = saveData.players.GetEnumerator();
						<>1__state = -3;
						goto IL_02c2;
					case 2:
						<>1__state = -3;
						saveManagerMod.playersBeingLoaded.Remove(<playerData>5__5.actorNumber);
						<successCount>5__2++;
						<>2__current = (object)new WaitForSeconds(0.5f);
						<>1__state = 3;
						return true;
					case 3:
						{
							<>1__state = -3;
							goto IL_02bb;
						}
						IL_02c2:
						if (<>7__wrap3.MoveNext())
						{
							<playerData>5__5 = <>7__wrap3.Current;
							Player val = saveManagerMod.FindPlayerByActorNumber(<playerData>5__5.actorNumber);
							if ((Object)(object)val != (Object)null)
							{
								Logger.LogInfo((object)$"Loading data for player: {<playerData>5__5.playerName} (Actor: {<playerData>5__5.actorNumber})");
								saveManagerMod.playersBeingLoaded.Add(<playerData>5__5.actorNumber);
								<>2__current = ((MonoBehaviour)saveManagerMod).StartCoroutine(saveManagerMod.ApplyPlayerDataCoroutine(val, <playerData>5__5));
								<>1__state = 2;
								return true;
							}
							Logger.LogWarning((object)$"Could not find player with actor number: {<playerData>5__5.actorNumber} ({<playerData>5__5.playerName})");
							goto IL_02bb;
						}
						<>m__Finally1();
						<>7__wrap3 = default(List<PlayerSaveData>.Enumerator);
						saveManagerMod.isLoading = false;
						if (<successCount>5__2 > 0)
						{
							saveManagerMod.ShowStatusMessage($"Loaded {<successCount>5__2}/{<totalPlayers>5__3} players successfully", 3f);
							Logger.LogInfo((object)$"Successfully loaded {<successCount>5__2}/{<totalPlayers>5__3} players");
						}
						else
						{
							saveManagerMod.ShowStatusMessage("Failed to load any players", 3f);
							Logger.LogWarning((object)"Failed to load any players");
						}
						return false;
						IL_02bb:
						<playerData>5__5 = null;
						goto IL_02c2;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>7__wrap3).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ApplyPlayerDataCoroutine>d__46 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public PlayerSaveData data;

			public Player player;

			public SaveManagerMod <>4__this;

			private Character <character>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ApplyPlayerDataCoroutine>d__46(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<character>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_0295: Unknown result type (might be due to invalid IL or missing references)
				//IL_029f: Expected O, but got Unknown
				//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0205: Expected O, but got Unknown
				int num = <>1__state;
				SaveManagerMod saveManagerMod = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Logger.LogInfo((object)$"Starting to apply data for {data.playerName} (Actor: {data.actorNumber})");
					<character>5__2 = player.character;
					if ((Object)(object)<character>5__2 == (Object)null)
					{
						Logger.LogError((object)("No character component found for player " + data.playerName));
						return false;
					}
					Logger.LogInfo((object)$"Character state before load - Dead: {<character>5__2.data.dead}, PassedOut: {<character>5__2.data.passedOut}, FullyPassedOut: {<character>5__2.data.fullyPassedOut}");
					Logger.LogInfo((object)$"Target position: {data.position.ToVector3()}, Current position: {((Component)<character>5__2).transform.position}");
					if (<character>5__2.data.dead || <character>5__2.data.fullyPassedOut)
					{
						Logger.LogInfo((object)("Player " + data.playerName + " is dead or passed out, checking if we should revive..."));
						if (data.characterState != null && !data.characterState.dead && !data.characterState.fullyPassedOut)
						{
							Logger.LogInfo((object)("Reviving player " + data.playerName + " to match saved state"));
							((MonoBehaviourPun)<character>5__2).photonView.RPC("RPCA_Revive", (RpcTarget)0, new object[1] { false });
							<>2__current = (object)new WaitForSeconds(1f);
							<>1__state = 1;
							return true;
						}
						Logger.LogInfo((object)("Skipping position load for " + data.playerName + " - player should remain dead/passed out"));
						saveManagerMod.ApplyInventoryData(player, data.inventory);
						return false;
					}
					goto IL_0254;
				case 1:
					<>1__state = -1;
					goto IL_0254;
				case 2:
					<>1__state = -1;
					<>2__current = ((MonoBehaviour)saveManagerMod).StartCoroutine(saveManagerMod.ApplyPlayerPositionCoroutine(<character>5__2, data));
					<>1__state = 3;
					return true;
				case 3:
					{
						<>1__state = -1;
						Logger.LogInfo((object)("Finished applying all data for player: " + data.playerName));
						return false;
					}
					IL_0254:
					saveManagerMod.ApplyInventoryData(player, data.inventory);
					if (data.characterState != null)
					{
						saveManagerMod.ApplyCharacterState(<character>5__2, data.characterState);
					}
					<>2__current = (object)new WaitForSeconds(0.5f);
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ApplyPlayerPositionCoroutine>d__49 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public PlayerSaveData data;

			public Character character;

			public SaveManagerMod <>4__this;

			private Vector3 <targetRotation>5__2;

			private Vector3 <safePosition>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ApplyPlayerPositionCoroutine>d__49(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0156: Unknown result type (might be due to invalid IL or missing references)
				//IL_0175: Unknown result type (might be due to invalid IL or missing references)
				//IL_017f: Expected O, but got Unknown
				//IL_019a: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
				//IL_030c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0322: Unknown result type (might be due to invalid IL or missing references)
				//IL_0228: Unknown result type (might be due to invalid IL or missing references)
				//IL_0258: Unknown result type (might be due to invalid IL or missing references)
				//IL_024c: Unknown result type (might be due to invalid IL or missing references)
				//IL_025d: Unknown result type (might be due to invalid IL or missing references)
				//IL_038c: Unknown result type (might be due to invalid IL or missing references)
				//IL_039d: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
				int num = <>1__state;
				SaveManagerMod saveManagerMod = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					Logger.LogInfo((object)("Starting position loading for " + data.playerName));
					Vector3 val = data.position.ToVector3();
					<targetRotation>5__2 = data.rotation.ToVector3();
					Logger.LogInfo((object)$"Target position: {val}, Target rotation: {<targetRotation>5__2}");
					Logger.LogInfo((object)$"Current position: {((Component)character).transform.position}, Current rotation: {((Component)character).transform.eulerAngles}");
					val.y += 2f;
					<safePosition>5__3 = saveManagerMod.FindSafeSpawnPosition(val);
					Logger.LogInfo((object)$"Safe position calculated: {<safePosition>5__3}");
					Player owner = ((MonoBehaviourPun)character).photonView.Owner;
					Logger.LogInfo((object)$"Sending WarpPlayerRPC to {owner.NickName} (Actor: {owner.ActorNumber})");
					((MonoBehaviourPun)character).photonView.RPC("WarpPlayerRPC", owner, new object[2] { <safePosition>5__3, false });
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				}
				case 1:
				{
					<>1__state = -1;
					float num2 = Vector3.Distance(((Component)character).transform.position, <safePosition>5__3);
					Logger.LogInfo((object)$"Position verification - Distance from target: {num2:F2}");
					if (num2 < 10f)
					{
						Logger.LogInfo((object)$"Position loaded successfully for {data.playerName}. Final position: {((Component)character).transform.position}");
						if (((MonoBehaviourPun)character).photonView.IsMine)
						{
							((Component)character).transform.eulerAngles = <targetRotation>5__2;
							character.data.lookValues = data.characterState?.lookValues.ToVector2() ?? Vector2.zero;
							CharacterAccessibilityPatches.CallRecalculateLookDirections(character);
						}
					}
					else
					{
						Logger.LogWarning((object)$"Position may not have loaded correctly for {data.playerName}. Distance from target: {num2:F2}");
						Logger.LogWarning((object)$"Expected: {<safePosition>5__3}, Actual: {((Component)character).transform.position}");
						if (((MonoBehaviourPun)character).photonView.IsMine)
						{
							Logger.LogInfo((object)("Attempting direct position setting for " + data.playerName));
							((Component)character).transform.position = <safePosition>5__3;
							((Component)character).transform.eulerAngles = <targetRotation>5__2;
							if ((Object)(object)character.refs.ragdoll != (Object)null)
							{
								foreach (Bodypart part in character.refs.ragdoll.partList)
								{
									if ((Object)(object)((part != null) ? part.Rig : null) != (Object)null)
									{
										part.Rig.position = <safePosition>5__3;
										part.Rig.linearVelocity = Vector3.zero;
										part.Rig.angularVelocity = Vector3.zero;
									}
								}
							}
						}
					}
					return false;
				}
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PLUGIN_GUID = "com.maxbridgland.peaksavemanager";

		public const string PLUGIN_NAME = "PEAK Save Manager";

		public const string PLUGIN_VERSION = "1.0.1";

		private static SaveManagerMod Instance;

		private static ManualLogSource Logger;

		private Harmony harmony;

		private ConfigEntry<KeyCode> toggleUIKey;

		private ConfigEntry<bool> autoSave;

		private ConfigEntry<float> autoSaveInterval;

		private Dictionary<int, PlayerSaveData> playerDataCache = new Dictionary<int, PlayerSaveData>();

		private string saveDirectory;

		private float lastAutoSave;

		private bool showUI;

		private Rect windowRect = new Rect(50f, 50f, 400f, 500f);

		private Vector2 scrollPosition = Vector2.zero;

		private string newSaveName = "";

		private List<SaveFileInfo> saveFiles = new List<SaveFileInfo>();

		private int selectedSaveIndex = -1;

		private string statusMessage = "";

		private float statusMessageTime;

		private bool isLoading;

		private HashSet<int> playersBeingLoaded = new HashSet<int>();

		private void Awake()
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			toggleUIKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "Toggle UI Key", (KeyCode)291, "Key to toggle save/load UI");
			autoSave = ((BaseUnityPlugin)this).Config.Bind<bool>("AutoSave", "Enable AutoSave", true, "Enable automatic saving");
			autoSaveInterval = ((BaseUnityPlugin)this).Config.Bind<float>("AutoSave", "AutoSave Interval", 300f, "AutoSave interval in seconds");
			saveDirectory = Path.Combine(Paths.GameRootPath, "PeakSaves");
			if (!Directory.Exists(saveDirectory))
			{
				Directory.CreateDirectory(saveDirectory);
			}
			harmony = new Harmony("com.maxbridgland.peaksavemanager");
			harmony.PatchAll();
			RefreshSaveFileList();
			Logger.LogInfo((object)"PEAK Save Manager 1.0.1 loaded!");
		}

		private void Update()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			if (Input.GetKeyDown(toggleUIKey.Value))
			{
				showUI = !showUI;
				if (showUI)
				{
					RefreshSaveFileList();
					EnableUIMode();
				}
				else
				{
					DisableUIMode();
				}
			}
			if (showUI)
			{
				BlockGameInput();
			}
			if (!showUI && !isLoading && autoSave.Value && Time.time - lastAutoSave > autoSaveInterval.Value)
			{
				SaveGameState("autosave");
				lastAutoSave = Time.time;
			}
			if (statusMessageTime > 0f)
			{
				statusMessageTime -= Time.deltaTime;
				if (statusMessageTime <= 0f)
				{
					statusMessage = "";
				}
			}
		}

		private void EnableUIMode()
		{
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
			Logger.LogInfo((object)"UI Mode enabled - cursor unlocked");
		}

		private void DisableUIMode()
		{
			Logger.LogInfo((object)"UI Mode disabled - returning control to game");
		}

		private void BlockGameInput()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			if ((int)Cursor.lockState != 0)
			{
				Cursor.lockState = (CursorLockMode)0;
			}
			if (!Cursor.visible)
			{
				Cursor.visible = true;
			}
		}

		private void LateUpdate()
		{
			if (showUI)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		private void OnGUI()
		{
			//IL_002b: 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_0046: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Invalid comparison between Unknown and I4
			//IL_005d: 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_006f: Invalid comparison between Unknown and I4
			if (showUI && PhotonNetwork.IsMasterClient)
			{
				GUI.skin = GUI.skin;
				GUI.FocusWindow(12345);
				windowRect = GUI.Window(12345, windowRect, new WindowFunction(DrawSaveLoadWindow), "PEAK Save/Load Manager");
				if ((int)Event.current.type == 4 || (int)Event.current.type == 0 || (int)Event.current.type == 1)
				{
					Event.current.Use();
				}
			}
		}

		private void DrawSaveLoadWindow(int windowID)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0376: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0469: Unknown result type (might be due to invalid IL or missing references)
			GUI.BringWindowToFront(windowID);
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			if (!string.IsNullOrEmpty(statusMessage))
			{
				GUI.color = Color.green;
				GUILayout.Label(statusMessage, GUI.skin.box, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
			}
			if (isLoading)
			{
				GUI.color = Color.yellow;
				GUILayout.Label("Loading game state... Please wait.", GUI.skin.box, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
			}
			GUILayout.Label("Save Game", GUI.skin.box, Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("Save Name:", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			newSaveName = GUILayout.TextField(newSaveName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = !isLoading;
			if (GUILayout.Button("Quick Save", Array.Empty<GUILayoutOption>()))
			{
				SaveGameState($"quicksave_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}");
			}
			GUI.enabled = !string.IsNullOrEmpty(newSaveName.Trim()) && !isLoading;
			if (GUILayout.Button("Save with Name", Array.Empty<GUILayoutOption>()))
			{
				SaveGameState(newSaveName.Trim());
				newSaveName = "";
			}
			GUI.enabled = !isLoading;
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			GUILayout.Label("Load Game", GUI.skin.box, Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Refresh Save List", Array.Empty<GUILayoutOption>()))
			{
				RefreshSaveFileList();
			}
			GUILayout.Label($"Save Files ({saveFiles.Count}):", Array.Empty<GUILayoutOption>());
			scrollPosition = GUILayout.BeginScrollView(scrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(250f) });
			for (int i = 0; i < saveFiles.Count; i++)
			{
				SaveFileInfo saveFileInfo = saveFiles[i];
				GUILayout.BeginHorizontal(GUI.skin.box, Array.Empty<GUILayoutOption>());
				bool flag = selectedSaveIndex == i;
				bool flag2 = GUILayout.Toggle(flag, "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(20f) });
				if (flag2 != flag)
				{
					selectedSaveIndex = (flag2 ? i : (-1));
				}
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				GUILayout.Label(saveFileInfo.displayName, GUI.skin.label, Array.Empty<GUILayoutOption>());
				GUI.color = Color.gray;
				GUILayout.Label($"Saved: {saveFileInfo.saveTime:yyyy-MM-dd HH:mm:ss}", GUI.skin.label, Array.Empty<GUILayoutOption>());
				GUILayout.Label($"Players: {saveFileInfo.playerCount}", GUI.skin.label, Array.Empty<GUILayoutOption>());
				GUI.color = Color.white;
				GUILayout.EndVertical();
				GUILayout.FlexibleSpace();
				GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
				if (GUILayout.Button("Load", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(20f) }))
				{
					LoadGameState(saveFileInfo.fileName);
				}
				GUI.color = Color.red;
				if (GUILayout.Button("Delete", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(20f) }))
				{
					DeleteSaveFile(saveFileInfo);
				}
				GUI.color = Color.white;
				GUILayout.EndVertical();
				GUILayout.EndHorizontal();
				GUILayout.Space(2f);
			}
			GUILayout.EndScrollView();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUI.enabled = selectedSaveIndex >= 0 && !isLoading;
			if (GUILayout.Button("Load Selected", Array.Empty<GUILayoutOption>()) && selectedSaveIndex >= 0 && selectedSaveIndex < saveFiles.Count)
			{
				LoadGameState(saveFiles[selectedSaveIndex].fileName);
			}
			GUI.color = Color.red;
			if (GUILayout.Button("Delete Selected", Array.Empty<GUILayoutOption>()) && selectedSaveIndex >= 0 && selectedSaveIndex < saveFiles.Count)
			{
				DeleteSaveFile(saveFiles[selectedSaveIndex]);
			}
			GUI.color = Color.white;
			GUI.enabled = !isLoading;
			GUILayout.EndHorizontal();
			GUILayout.Space(10f);
			if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
			{
				showUI = false;
			}
			GUILayout.EndVertical();
			GUI.DragWindow();
		}

		private void RefreshSaveFileList()
		{
			saveFiles.Clear();
			selectedSaveIndex = -1;
			try
			{
				foreach (string item in from f in Directory.GetFiles(saveDirectory, "*.json")
					orderby File.GetLastWriteTime(f) descending
					select f)
				{
					try
					{
						string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item);
						FileInfo fileInfo = new FileInfo(item);
						GameSaveData gameSaveData = JsonConvert.DeserializeObject<GameSaveData>(File.ReadAllText(item));
						saveFiles.Add(new SaveFileInfo
						{
							fileName = fileNameWithoutExtension,
							displayName = fileNameWithoutExtension.Replace("_", " "),
							filePath = item,
							saveTime = gameSaveData.saveTime,
							playerCount = gameSaveData.players.Count,
							fileSize = fileInfo.Length
						});
					}
					catch (Exception ex)
					{
						Logger.LogWarning((object)("Could not read save file " + item + ": " + ex.Message));
					}
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error refreshing save file list: {arg}");
				ShowStatusMessage("Error loading save files!", 3f);
			}
		}

		private void DeleteSaveFile(SaveFileInfo saveFile)
		{
			try
			{
				File.Delete(saveFile.filePath);
				RefreshSaveFileList();
				ShowStatusMessage("Deleted: " + saveFile.displayName);
				Logger.LogInfo((object)("Deleted save file: " + saveFile.fileName));
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error deleting save file: {arg}");
				ShowStatusMessage("Error deleting file!", 3f);
			}
		}

		private void ShowStatusMessage(string message, float duration = 2f)
		{
			statusMessage = message;
			statusMessageTime = duration;
		}

		private static Vector3 GetCharacterActualPosition(Character character)
		{
			//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_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: 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_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = Vector3.zero;
			string arg = "unknown";
			try
			{
				if (character.Center != Vector3.zero)
				{
					val = character.Center;
					arg = "Center (torso)";
				}
				else if ((Object)(object)character.refs.ragdoll != (Object)null && (Object)(object)character.refs.hip != (Object)null && (Object)(object)character.refs.hip.Rig != (Object)null)
				{
					val = character.refs.hip.Rig.position;
					arg = "Hip rigidbody";
				}
				else if ((Object)(object)character.refs.ragdoll != (Object)null && character.refs.ragdoll.partList != null)
				{
					Vector3 val2 = Vector3.zero;
					int num = 0;
					foreach (Bodypart part in character.refs.ragdoll.partList)
					{
						if ((Object)(object)((part != null) ? part.Rig : null) != (Object)null)
						{
							val2 += part.Rig.position;
							num++;
						}
					}
					if (num > 0)
					{
						val = val2 / (float)num;
						arg = $"Average of {num} body parts";
					}
				}
				if (val == Vector3.zero)
				{
					val = ((Component)character).transform.position;
					arg = "Transform position (fallback)";
				}
				Logger.LogInfo((object)$"Got character position from {arg}: {val}");
				return val;
			}
			catch (Exception arg2)
			{
				Logger.LogError((object)$"Error getting character position: {arg2}");
				return ((Component)character).transform.position;
			}
		}

		private static Vector3 GetCharacterActualRotation(Character character)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (character.data.lookDirection != Vector3.zero)
				{
					Quaternion val = Quaternion.LookRotation(character.data.lookDirection_Flat);
					return ((Quaternion)(ref val)).eulerAngles;
				}
				return ((Component)character).transform.eulerAngles;
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error getting character rotation: {arg}");
				return ((Component)character).transform.eulerAngles;
			}
		}

		public static void UpdatePlayerData(Player player)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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)
			//IL_005c: 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_00b9: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Instance == (Object)null || !PhotonNetwork.IsMasterClient)
			{
				return;
			}
			try
			{
				Character character = player.character;
				if ((Object)(object)character == (Object)null)
				{
					Logger.LogWarning((object)("No character found for player " + ((MonoBehaviourPun)player).photonView.Owner.NickName));
					return;
				}
				Vector3 characterActualPosition = GetCharacterActualPosition(character);
				Vector3 characterActualRotation = GetCharacterActualRotation(character);
				Logger.LogInfo((object)$"Updating player data for {((MonoBehaviourPun)player).photonView.Owner.NickName} at position {characterActualPosition}");
				PlayerSaveData value = new PlayerSaveData
				{
					playerName = ((MonoBehaviourPun)player).photonView.Owner.NickName,
					actorNumber = ((MonoBehaviourPun)player).photonView.Owner.ActorNumber,
					position = new Vector3Data(characterActualPosition),
					rotation = new Vector3Data(characterActualRotation),
					mapId = GetCurrentMapId(),
					inventory = ConvertInventoryToSaveData(player),
					characterState = new CharacterStateData
					{
						isGrounded = character.data.isGrounded,
						sinceGrounded = character.data.sinceGrounded,
						groundPos = new Vector3Data(character.data.groundPos),
						groundNormal = new Vector3Data(character.data.groundNormal),
						currentStamina = character.data.currentStamina,
						extraStamina = character.data.extraStamina,
						passedOut = character.data.passedOut,
						fullyPassedOut = character.data.fullyPassedOut,
						dead = character.data.dead,
						isClimbing = character.data.isClimbing,
						isRopeClimbing = character.data.isRopeClimbing,
						isVineClimbing = character.data.isVineClimbing,
						isSprinting = character.data.isSprinting,
						lookValues = new Vector2Data(character.data.lookValues)
					}
				};
				Instance.playerDataCache[((MonoBehaviourPun)player).photonView.Owner.ActorNumber] = value;
				Logger.LogInfo((object)$"Successfully cached position {characterActualPosition} for player {((MonoBehaviourPun)player).photonView.Owner.NickName}");
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error updating player data: {arg}");
			}
		}

		private static InventoryData ConvertInventoryToSaveData(Player player)
		{
			InventoryData inventoryData = new InventoryData();
			for (int i = 0; i < player.itemSlots.Length; i++)
			{
				ItemSlot val = player.itemSlots[i];
				inventoryData.itemSlots.Add(new ItemSlotData
				{
					slotId = (byte)i,
					itemId = (val.prefab?.itemID ?? ushort.MaxValue),
					instanceDataGuid = val.data?.guid.ToString(),
					instanceData = ConvertInstanceData(val.data)
				});
			}
			inventoryData.tempSlot = new ItemSlotData
			{
				slotId = 250,
				itemId = (player.tempFullSlot.prefab?.itemID ?? ushort.MaxValue),
				instanceDataGuid = player.tempFullSlot.data?.guid.ToString(),
				instanceData = ConvertInstanceData(player.tempFullSlot.data)
			};
			inventoryData.backpack = new BackpackData
			{
				hasBackpack = player.backpackSlot.hasBackpack,
				instanceDataGuid = ((ItemSlot)player.backpackSlot).data?.guid.ToString(),
				instanceData = ConvertInstanceData(((ItemSlot)player.backpackSlot).data)
			};
			return inventoryData;
		}

		private static Dictionary<string, object> ConvertInstanceData(ItemInstanceData data)
		{
			//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)
			if (data?.data == null)
			{
				return null;
			}
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			foreach (KeyValuePair<DataEntryKey, DataEntryValue> datum in data.data)
			{
				DataEntryKey key = datum.Key;
				dictionary[((object)(DataEntryKey)(ref key)).ToString()] = SerializeDataEntryValue(datum.Value);
			}
			return dictionary;
		}

		private static object SerializeDataEntryValue(DataEntryValue value)
		{
			if (value == null)
			{
				return null;
			}
			return new Dictionary<string, object>
			{
				["type"] = ((object)value).GetType().Name,
				["data"] = ((object)value).ToString()
			};
		}

		private static string GetCurrentMapId()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			return ((Scene)(ref activeScene)).name;
		}

		private string SegmentToString(Segment segment)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected I4, but got Unknown
			return (int)segment switch
			{
				2 => "alpine", 
				5 => "peak", 
				0 => "beach", 
				1 => "tropics", 
				4 => "kiln", 
				3 => "caldera", 
				_ => "beach", 
			};
		}

		private Segment StringToSegment(string str)
		{
			return (Segment)(str switch
			{
				"alpine" => 2, 
				"peak" => 5, 
				"beach" => 0, 
				"tropics" => 1, 
				"kiln" => 4, 
				"caldera" => 3, 
				_ => 0, 
			});
		}

		private void SaveGameState(string fileName)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Logger.LogInfo((object)("Starting save process for: " + fileName));
				Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
				Logger.LogInfo((object)$"Found {array.Length} players to save");
				Player[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					UpdatePlayerData(array2[i]);
				}
				Segment currentSegment = Object.FindFirstObjectByType<MapHandler>().GetCurrentSegment();
				GameSaveData gameSaveData = new GameSaveData
				{
					saveTime = DateTime.Now,
					players = new List<PlayerSaveData>(playerDataCache.Values),
					mapSegment = SegmentToString(currentSegment)
				};
				string contents = JsonConvert.SerializeObject((object)gameSaveData, (Formatting)1);
				string text = Path.Combine(saveDirectory, fileName + ".json");
				File.WriteAllText(text, contents);
				Logger.LogInfo((object)$"Game saved to: {text} with {gameSaveData.players.Count} players");
				ShowStatusMessage("Saved: " + fileName);
				RefreshSaveFileList();
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error saving game: {arg}");
				ShowStatusMessage("Save failed!", 3f);
			}
		}

		private void LoadGameState(string fileName)
		{
			if (isLoading)
			{
				ShowStatusMessage("Already loading a save!", 3f);
				return;
			}
			try
			{
				string text = Path.Combine(saveDirectory, fileName + ".json");
				if (!File.Exists(text))
				{
					Logger.LogWarning((object)("Save file not found: " + text));
					ShowStatusMessage("Save file not found!", 3f);
					return;
				}
				GameSaveData gameSaveData = JsonConvert.DeserializeObject<GameSaveData>(File.ReadAllText(text));
				isLoading = true;
				Logger.LogInfo((object)$"Starting load process for: {fileName} with {gameSaveData.players.Count} players");
				((MonoBehaviour)this).StartCoroutine(ApplyLoadedDataCoroutine(gameSaveData, fileName));
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error loading game: {arg}");
				ShowStatusMessage("Load failed!", 3f);
				isLoading = false;
			}
		}

		[IteratorStateMachine(typeof(<ApplyLoadedDataCoroutine>d__44))]
		private IEnumerator ApplyLoadedDataCoroutine(GameSaveData saveData, string fileName)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ApplyLoadedDataCoroutine>d__44(0)
			{
				<>4__this = this,
				saveData = saveData,
				fileName = fileName
			};
		}

		private Player FindPlayerByActorNumber(int actorNumber)
		{
			Player[] array = Object.FindObjectsByType<Player>((FindObjectsSortMode)0);
			foreach (Player val in array)
			{
				PhotonView photonView = ((MonoBehaviourPun)val).photonView;
				if (photonView != null)
				{
					Player owner = photonView.Owner;
					if (((owner != null) ? new int?(owner.ActorNumber) : null) == actorNumber)
					{
						Logger.LogInfo((object)$"Found player {((MonoBehaviourPun)val).photonView.Owner.NickName} with actor number {actorNumber}");
						return val;
					}
				}
			}
			Character[] array2 = Object.FindObjectsByType<Character>((FindObjectsSortMode)0);
			foreach (Character val2 in array2)
			{
				PhotonView photonView2 = ((MonoBehaviourPun)val2).photonView;
				if (photonView2 == null)
				{
					continue;
				}
				Player owner2 = photonView2.Owner;
				if (((owner2 != null) ? new int?(owner2.ActorNumber) : null) == actorNumber)
				{
					Player component = ((Component)val2).GetComponent<Player>();
					if ((Object)(object)component != (Object)null)
					{
						Logger.LogInfo((object)$"Found player {((MonoBehaviourPun)val2).photonView.Owner.NickName} via character lookup with actor number {actorNumber}");
						return component;
					}
				}
			}
			Logger.LogWarning((object)$"Could not find player with actor number {actorNumber}");
			return null;
		}

		[IteratorStateMachine(typeof(<ApplyPlayerDataCoroutine>d__46))]
		private IEnumerator ApplyPlayerDataCoroutine(Player player, PlayerSaveData data)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ApplyPlayerDataCoroutine>d__46(0)
			{
				<>4__this = this,
				player = player,
				data = data
			};
		}

		private void ApplyCharacterState(Character character, CharacterStateData stateData)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Logger.LogInfo((object)("Applying character state for " + character.characterName));
				character.data.currentStamina = stateData.currentStamina;
				character.data.extraStamina = stateData.extraStamina;
				character.data.isGrounded = stateData.isGrounded;
				character.data.sinceGrounded = stateData.sinceGrounded;
				character.data.groundPos = stateData.groundPos.ToVector3();
				character.data.groundNormal = stateData.groundNormal.ToVector3();
				character.data.isClimbing = stateData.isClimbing;
				character.data.isRopeClimbing = stateData.isRopeClimbing;
				character.data.isVineClimbing = stateData.isVineClimbing;
				character.data.isSprinting = stateData.isSprinting;
				character.data.lookValues = stateData.lookValues.ToVector2();
				CharacterAccessibilityPatches.CallRecalculateLookDirections(character);
				Logger.LogInfo((object)("Character state applied successfully for " + character.characterName));
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error applying character state: {arg}");
			}
		}

		private void ApplyInventoryData(Player player, InventoryData inventoryData)
		{
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Logger.LogInfo((object)$"Loading inventory for player {((MonoBehaviourPun)player).photonView.Owner.NickName} with {inventoryData.itemSlots.Count} item slots");
				for (int i = 0; i < player.itemSlots.Length; i++)
				{
					player.itemSlots[i].EmptyOut();
				}
				player.tempFullSlot.EmptyOut();
				((ItemSlot)player.backpackSlot).EmptyOut();
				for (int j = 0; j < inventoryData.itemSlots.Count && j < player.itemSlots.Length; j++)
				{
					ItemSlotData itemSlotData = inventoryData.itemSlots[j];
					if (itemSlotData.itemId != ushort.MaxValue)
					{
						LoadItemToSlot(player.itemSlots[j], itemSlotData);
					}
				}
				if (inventoryData.tempSlot.itemId != ushort.MaxValue)
				{
					LoadItemToSlot(player.tempFullSlot, inventoryData.tempSlot);
				}
				if (inventoryData.backpack.hasBackpack)
				{
					player.backpackSlot.hasBackpack = true;
					if (!string.IsNullOrEmpty(inventoryData.backpack.instanceDataGuid))
					{
						Guid guid = Guid.Parse(inventoryData.backpack.instanceDataGuid);
						ItemInstanceData orCreateInstanceData = GetOrCreateInstanceData(guid, inventoryData.backpack.instanceData);
						((ItemSlot)player.backpackSlot).data = orCreateInstanceData;
					}
				}
				InventorySyncData val = default(InventorySyncData);
				((InventorySyncData)(ref val))..ctor(player.itemSlots, player.backpackSlot, player.tempFullSlot);
				((MonoBehaviourPun)player).photonView.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
				{
					IBinarySerializable.ToManagedArray<InventorySyncData>(val),
					true
				});
				Logger.LogInfo((object)("Inventory loaded successfully for " + ((MonoBehaviourPun)player).photonView.Owner.NickName));
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error loading inventory: {arg}");
			}
		}

		[IteratorStateMachine(typeof(<ApplyPlayerPositionCoroutine>d__49))]
		private IEnumerator ApplyPlayerPositionCoroutine(Character character, PlayerSaveData data)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ApplyPlayerPositionCoroutine>d__49(0)
			{
				<>4__this = this,
				character = character,
				data = data
			};
		}

		private Vector3 FindSafeSpawnPosition(Vector3 originalPosition)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_0074: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: 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)
			try
			{
				Vector3 val = new Vector3(originalPosition.x, originalPosition.y + 100f, originalPosition.z);
				RaycastHit val2 = HelperFunctions.LineCheck(val, val + Vector3.down * 200f, (LayerType)1, 0f, (QueryTriggerInteraction)1);
				if ((Object)(object)((RaycastHit)(ref val2)).transform != (Object)null)
				{
					Vector3 val3 = ((RaycastHit)(ref val2)).point + Vector3.up * 2f;
					Logger.LogInfo((object)$"Found safe spawn position: {val3} (original: {originalPosition})");
					return val3;
				}
				Logger.LogWarning((object)$"No ground found for position {originalPosition}, using original + offset");
				return originalPosition + Vector3.up * 5f;
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error finding safe spawn position: {arg}");
				return originalPosition + Vector3.up * 5f;
			}
		}

		private void LoadItemToSlot(ItemSlot slot, ItemSlotData slotData)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			try
			{
				Item val = default(Item);
				if (!ItemDatabase.TryGetItem(slotData.itemId, ref val))
				{
					Logger.LogWarning((object)$"Could not find item with ID: {slotData.itemId}");
					return;
				}
				ItemInstanceData val2 = null;
				if (!string.IsNullOrEmpty(slotData.instanceDataGuid))
				{
					Guid guid = Guid.Parse(slotData.instanceDataGuid);
					val2 = GetOrCreateInstanceData(guid, slotData.instanceData);
				}
				else
				{
					val2 = new ItemInstanceData(Guid.NewGuid());
					ItemInstanceDataHandler.AddInstanceData(val2);
				}
				slot.SetItem(val, val2);
				Logger.LogInfo((object)$"Loaded item {((Object)val).name} to slot {slotData.slotId}");
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error loading item to slot: {arg}");
			}
		}

		private ItemInstanceData GetOrCreateInstanceData(Guid guid, Dictionary<string, object> savedData)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			ItemInstanceData result = default(ItemInstanceData);
			if (ItemInstanceDataHandler.TryGetInstanceData(guid, ref result))
			{
				return result;
			}
			result = new ItemInstanceData(guid);
			if (savedData != null)
			{
				foreach (KeyValuePair<string, object> savedDatum in savedData)
				{
					try
					{
						if (Enum.TryParse<DataEntryKey>(savedDatum.Key, out DataEntryKey result2))
						{
							Logger.LogInfo((object)$"Restoring data entry: {result2}");
						}
					}
					catch (Exception ex)
					{
						Logger.LogWarning((object)("Could not restore data entry " + savedDatum.Key + ": " + ex.Message));
					}
				}
			}
			ItemInstanceDataHandler.AddInstanceData(result);
			return result;
		}

		private void OnDestroy()
		{
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	[Serializable]
	public class PlayerSaveData
	{
		public string playerName;

		public int actorNumber;

		public Vector3Data position;

		public Vector3Data rotation;

		public string mapId;

		public InventoryData inventory;

		public CharacterStateData characterState;
	}
	[Serializable]
	public class CharacterStateData
	{
		public bool isGrounded;

		public float sinceGrounded;

		public Vector3Data groundPos;

		public Vector3Data groundNormal;

		public float currentStamina;

		public float extraStamina;

		public bool passedOut;

		public bool fullyPassedOut;

		public bool dead;

		public bool isClimbing;

		public bool isRopeClimbing;

		public bool isVineClimbing;

		public bool isSprinting;

		public Vector2Data lookValues;
	}
	[Serializable]
	public class Vector3Data
	{
		public float x;

		public float y;

		public float z;

		public Vector3Data()
		{
		}

		public Vector3Data(Vector3 vector)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			x = vector.x;
			y = vector.y;
			z = vector.z;
		}

		public Vector3 ToVector3()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(x, y, z);
		}
	}
	[Serializable]
	public class Vector2Data
	{
		public float x;

		public float y;

		public Vector2Data()
		{
		}

		public Vector2Data(Vector2 vector)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			x = vector.x;
			y = vector.y;
		}

		public Vector2 ToVector2()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(x, y);
		}
	}
	[Serializable]
	public class InventoryData
	{
		public List<ItemSlotData> itemSlots = new List<ItemSlotData>();

		public ItemSlotData tempSlot;

		public BackpackData backpack;
	}
	[Serializable]
	public class ItemSlotData
	{
		public byte slotId;

		public ushort itemId;

		public string instanceDataGuid;

		public Dictionary<string, object> instanceData;
	}
	[Serializable]
	public class BackpackData
	{
		public bool hasBackpack;

		public string instanceDataGuid;

		public Dictionary<string, object> instanceData;
	}
	[Serializable]
	public class GameSaveData
	{
		public string saveVersion = "1.0";

		public string saveName;

		public DateTime saveTime;

		public List<PlayerSaveData> players = new List<PlayerSaveData>();

		public string mapSegment;
	}
	[Serializable]
	public class SaveFileInfo
	{
		public string fileName;

		public string displayName;

		public string filePath;

		public DateTime saveTime;

		public int playerCount;

		public long fileSize;
	}
}
namespace PEAKSaveManager.Patches
{
	[HarmonyPatch]
	public class CharacterAccessibilityPatches
	{
		private static MethodInfo recalculateMethod;

		static CharacterAccessibilityPatches()
		{
			recalculateMethod = typeof(Character).GetMethod("RecalculateLookDirections", BindingFlags.Instance | BindingFlags.NonPublic);
		}

		public static void CallRecalculateLookDirections(Character character)
		{
			try
			{
				recalculateMethod?.Invoke(character, null);
			}
			catch (Exception arg)
			{
				Logger.CreateLogSource("CharacterPatches").LogError((object)$"Error calling RecalculateLookDirections: {arg}");
			}
		}
	}
	[HarmonyPatch]
	internal class CharacterPatches
	{
		private static ManualLogSource Logger => Logger.CreateLogSource("PlayerPatches");

		[HarmonyPatch(typeof(Character), "WarpPlayerRPC")]
		[HarmonyPrefix]
		public static bool WarpPlayerRPC_Prefix(Character __instance, Vector3 position)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Logger.LogInfo((object)$"WarpPlayerRPC called for character {((Object)__instance).name} at {((Component)__instance).transform.position} to {position}");
				return true;
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"Error in Character WarpPlayerRPC patch: {arg}");
				return true;
			}
		}
	}
	[HarmonyPatch]
	public class PlayerPatches
	{
		[CompilerGenerated]
		private sealed class <DelayedUpdatePlayerData>d__7 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public Player player;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedUpdatePlayerData>d__7(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					SaveManagerMod.UpdatePlayerData(player);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private static ManualLogSource Logger => Logger.CreateLogSource("PlayerPatches");

		[HarmonyPatch(typeof(Character), "FixedUpdate")]
		[HarmonyPostfix]
		public static void FixedUpdate_Postfix(Character __instance)
		{
			if (__instance.IsLocal && Time.fixedTime % 1f < Time.fixedDeltaTime)
			{
				Player player = __instance.player;
				if ((Object)(object)player != (Object)null)
				{
					SaveManagerMod.UpdatePlayerData(player);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SyncInventoryRPC")]
		[HarmonyPostfix]
		public static void SyncInventoryRPC_Postfix(Player __instance)
		{
			SaveManagerMod.UpdatePlayerData(__instance);
		}

		[HarmonyPatch(typeof(Player), "AddItem")]
		[HarmonyPostfix]
		public static void AddItem_Postfix(Player __instance, bool __result)
		{
			if (__result)
			{
				SaveManagerMod.UpdatePlayerData(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "EmptySlot")]
		[HarmonyPostfix]
		public static void EmptySlot_Postfix(Player __instance)
		{
			SaveManagerMod.UpdatePlayerData(__instance);
		}

		[HarmonyPatch(typeof(Player), "Awake")]
		[HarmonyPostfix]
		public static void Awake_Postfix(Player __instance)
		{
			((MonoBehaviour)__instance).StartCoroutine(DelayedUpdatePlayerData(__instance));
		}

		[IteratorStateMachine(typeof(<DelayedUpdatePlayerData>d__7))]
		private static IEnumerator DelayedUpdatePlayerData(Player player)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedUpdatePlayerData>d__7(0)
			{
				player = player
			};
		}
	}
}