Decompiled source of SaveAnywhere v1.0.0

SaveAnywhere.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GameData;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using LevelGeneration;
using Microsoft.CodeAnalysis;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GTFOCheckpointPrototype")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+42eea22b2cc538ae364395df4e0684210c1cfa86")]
[assembly: AssemblyProduct("GTFOCheckpointPrototype")]
[assembly: AssemblyTitle("GTFOCheckpointPrototype")]
[assembly: AssemblyVersion("1.0.0.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 GTFOCheckpointPrototype
{
	public class GuiBehaviour : MonoBehaviour
	{
		private static string _message = "";

		private static float _messageUntil;

		private static GUIStyle _style;

		private static GuiBehaviour _instance;

		private static bool _overlayWasVisible;

		private static GUIStyle _headingStyle;

		private static GUIStyle _slotStyle;

		private static GUIStyle _seedStyle;

		private static GUIStyle _dateTimeStyle;

		private static GUIStyle _cowStyle;

		private static GUIStyle _footerStyle;

		public GuiBehaviour(IntPtr ptr)
			: base(ptr)
		{
		}

		private void Awake()
		{
			_instance = this;
		}

		public static void QueueF8Apply()
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					((BasePlugin)instance).Log.LogWarning((object)"F8: GUI instance unavailable.");
				}
			}
			else
			{
				((MonoBehaviour)_instance).CancelInvoke("ApplyF8NextFrame");
				((MonoBehaviour)_instance).Invoke("ApplyF8NextFrame", 0f);
			}
		}

		private void ApplyF8NextFrame()
		{
			PlayerGuiLayerUpdatePatch.ExecuteQueuedF8();
		}

		private void EnsureStyle()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: 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_002b: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if (_style == null)
			{
				_style = new GUIStyle(GUI.skin.label)
				{
					fontSize = 24,
					alignment = (TextAnchor)1
				};
				_style.normal.textColor = Color.red;
			}
		}

		public void OnGUI()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyle();
			bool isSaveSlotSelectorVisible = PlayerGuiLayerUpdatePatch.IsSaveSlotSelectorVisible;
			if (isSaveSlotSelectorVisible && !_overlayWasVisible)
			{
				PlayerGuiLayerUpdatePatch.RefreshSaveSlotCache();
			}
			_overlayWasVisible = isSaveSlotSelectorVisible;
			if (isSaveSlotSelectorVisible)
			{
				DrawSaveSlotSelector();
			}
			if (!(Time.unscaledTime >= _messageUntil) && !string.IsNullOrEmpty(_message))
			{
				Vector2 val = _style.CalcSize(new GUIContent(_message));
				Rect val2 = new Rect(10f, 25f, val.x + 10f, 35f);
				GUI.color = Color.black;
				GUI.DrawTexture(val2, (Texture)(object)Texture2D.whiteTexture);
				GUI.color = _style.normal.textColor;
				GUI.Label(val2, _message, _style);
			}
		}

		private static void BuildOverlayStyles()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00dd: 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_0106: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			_headingStyle = new GUIStyle(GUI.skin.label);
			_headingStyle.fontSize = 22;
			_headingStyle.fontStyle = (FontStyle)1;
			_headingStyle.normal.textColor = Color.red;
			_headingStyle.alignment = (TextAnchor)4;
			_slotStyle = new GUIStyle(GUI.skin.label);
			_slotStyle.fontSize = 20;
			_slotStyle.alignment = (TextAnchor)4;
			_slotStyle.normal.textColor = Color.red;
			_slotStyle.wordWrap = true;
			_seedStyle = new GUIStyle(GUI.skin.label);
			_seedStyle.fontSize = 11;
			_seedStyle.alignment = (TextAnchor)4;
			_seedStyle.normal.textColor = new Color(1f, 0.35f, 0.35f, 1f);
			_seedStyle.wordWrap = false;
			_dateTimeStyle = new GUIStyle(GUI.skin.label);
			_dateTimeStyle.fontSize = 10;
			_dateTimeStyle.alignment = (TextAnchor)4;
			_dateTimeStyle.normal.textColor = new Color(1f, 0.55f, 0.55f, 1f);
			_dateTimeStyle.wordWrap = false;
			_cowStyle = new GUIStyle(GUI.skin.label);
			_cowStyle.fontSize = 7;
			_cowStyle.alignment = (TextAnchor)4;
			_cowStyle.normal.textColor = Color.red;
			_footerStyle = new GUIStyle(GUI.skin.label);
			_footerStyle.fontSize = 18;
			_footerStyle.alignment = (TextAnchor)4;
			_footerStyle.normal.textColor = Color.red;
		}

		private static void DrawSaveSlotSelector()
		{
			//IL_004f: 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_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: 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_01f8: Unknown result type (might be due to invalid IL or missing references)
			if (_headingStyle == null)
			{
				BuildOverlayStyles();
			}
			float num = 798f;
			float num2 = ((float)Screen.width - num) * 0.5f;
			float num3 = Mathf.Max(150f, (float)Screen.height * 0.48f);
			GUI.Label(new Rect(0f, num3 - 48f, (float)Screen.width, 34f), "Select a save slot with the arrow keys", _headingStyle);
			GUI.Label(new Rect((float)Screen.width - 40f, (float)Screen.height - 35f, 50f, 45f), "MT", _cowStyle);
			for (int i = 0; i < 5; i++)
			{
				float num4 = num2 + (float)i * 162f;
				Rect val = new Rect(num4, num3, 150f, 112f);
				GUI.color = ((i == PlayerGuiLayerUpdatePatch.SelectedSaveSlot) ? new Color(0.3f, 0.02f, 0.02f, 0.96f) : new Color(0f, 0f, 0f, 0.92f));
				GUI.DrawTexture(val, (Texture)(object)Texture2D.whiteTexture);
				GUI.color = Color.red;
				GUI.Box(val, GUIContent.none);
				string saveSlotDateTimeLabel = PlayerGuiLayerUpdatePatch.GetSaveSlotDateTimeLabel(i);
				if (!string.IsNullOrEmpty(saveSlotDateTimeLabel))
				{
					GUI.Label(new Rect(num4 + 5f, num3 + 2f, 140f, 16f), saveSlotDateTimeLabel, _dateTimeStyle);
				}
				GUI.Label(new Rect(num4 + 5f, num3 + 18f, 140f, 34f), "SLOT " + (i + 1), _slotStyle);
				GUI.Label(new Rect(num4 + 5f, num3 + 50f, 140f, 42f), PlayerGuiLayerUpdatePatch.GetSaveSlotLabel(i), _slotStyle);
				string saveSlotSessionSeedLabel = PlayerGuiLayerUpdatePatch.GetSaveSlotSessionSeedLabel(i);
				if (!string.IsNullOrEmpty(saveSlotSessionSeedLabel))
				{
					GUI.Label(new Rect(num4 + 5f, num3 + 91f, 140f, 20f), saveSlotSessionSeedLabel, _seedStyle);
				}
			}
			GUI.color = Color.red;
			GUI.Label(new Rect(0f, num3 + 112f + 14f, (float)Screen.width, 30f), "F5 - Save     F8 - Force Seed     F9 - Load Solo     F10 - Load Multiplayer", _footerStyle);
			string overlaySeedStatus = PlayerGuiLayerUpdatePatch.GetOverlaySeedStatus();
			if (!string.IsNullOrEmpty(overlaySeedStatus))
			{
				GUI.Label(new Rect(0f, num3 + 112f + 43f, (float)Screen.width, 26f), overlaySeedStatus, _footerStyle);
			}
			GUI.color = Color.white;
		}

		public static void ShowTemporary(string message, float seconds)
		{
			_message = message;
			_messageUntil = Time.unscaledTime + seconds;
		}
	}
	[BepInPlugin("com.example.gtfocheckpointprototype", "GTFO Checkpoint Prototype", "1.0.0")]
	public class Plugin : BasePlugin
	{
		public static Plugin Instance { get; private set; }

		public override void Load()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			((BasePlugin)this).AddComponent<GuiBehaviour>();
			new Harmony("com.example.gtfocheckpointprototype").PatchAll();
			((BasePlugin)this).Log.LogInfo((object)"GTFO checkpoint mod loaded.");
		}
	}
	[HarmonyPatch(typeof(RundownManager), "MasterSelectActiveExpedition")]
	public static class RundownManagerMasterSelectActiveExpeditionPatch
	{
		public static void Postfix()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			try
			{
				if (PlayerGuiLayerUpdatePatch.IsF8Armed && SNet.IsMaster)
				{
					GuiBehaviour.QueueF8Apply();
				}
			}
			catch (Exception ex)
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F8 scheduling failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogError(val);
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerGuiLayer), "Update")]
	public static class PlayerGuiLayerUpdatePatch
	{
		private struct SaveSlotInfo
		{
			public string Label;

			public string SessionSeedLabel;

			public string DateTimeLabel;
		}

		private struct SavedMetadata
		{
			public string LevelId;

			public bool HasSeeds;

			public int HostIDSeed;

			public int SessionSeed;

			public bool HasSaveDateTime;

			public DateTime SaveDateTime;
		}

		private const int SaveSlotCount = 5;

		private static SNet_CaptureBuffer _clonedCheckpoint;

		private static bool _f8Armed;

		private static bool _f8AppliedThisSelection;

		private static int _f8SaveSlot;

		private static int _selectedSaveSlot;

		private static readonly SaveSlotInfo[] _saveSlotCache = new SaveSlotInfo[5];

		private static bool _forcingSeedKnown;

		private static int _forcingSeed;

		public static int SelectedSaveSlot => _selectedSaveSlot;

		public static bool IsSaveSlotSelectorVisible => Input.GetKey((KeyCode)96);

		public static bool IsF8Armed => _f8Armed;

		private static string GetCheckpointSavePath(int slot)
		{
			string path = Path.Combine(Paths.PluginPath, "SaveAnywhere");
			string path2 = ((slot == 0) ? "checkpoint.dat" : $"checkpoint-slot-{slot + 1}.dat");
			return Path.Combine(path, path2);
		}

		private static string GetSelectedCheckpointSavePath()
		{
			return GetCheckpointSavePath(_selectedSaveSlot);
		}

		private static void ChangeSelectedSaveSlot(int delta)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			_selectedSaveSlot = (_selectedSaveSlot + delta + 5) % 5;
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log = ((BasePlugin)instance).Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(35, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Slot selector: selected save slot ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_selectedSaveSlot + 1);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
		}

		public static void RefreshSaveSlotCache()
		{
			for (int i = 0; i < 5; i++)
			{
				SaveSlotInfo saveSlotInfo = default(SaveSlotInfo);
				string checkpointSavePath = GetCheckpointSavePath(i);
				if (!File.Exists(checkpointSavePath))
				{
					saveSlotInfo.Label = "EMPTY";
					saveSlotInfo.SessionSeedLabel = string.Empty;
					saveSlotInfo.DateTimeLabel = string.Empty;
				}
				else
				{
					SavedMetadata saved;
					bool flag = TryReadSavedMetadataFromPath(checkpointSavePath, out saved);
					saveSlotInfo.Label = ((flag && !string.IsNullOrEmpty(saved.LevelId)) ? saved.LevelId : "SAVED");
					saveSlotInfo.SessionSeedLabel = ((flag && saved.HasSeeds) ? ("SessionSeed: " + saved.SessionSeed) : "SessionSeed: unavailable");
					saveSlotInfo.DateTimeLabel = ((flag && saved.HasSaveDateTime) ? saved.SaveDateTime.ToString("dd/MM/yyyy HH:mm") : string.Empty);
				}
				_saveSlotCache[i] = saveSlotInfo;
			}
			_forcingSeedKnown = false;
			if (_f8Armed && TryReadSavedMetadataFromPath(GetCheckpointSavePath(_f8SaveSlot), out var saved2) && saved2.HasSeeds)
			{
				_forcingSeed = saved2.SessionSeed;
				_forcingSeedKnown = true;
			}
		}

		public static string GetSaveSlotLabel(int slot)
		{
			return _saveSlotCache[slot].Label;
		}

		public static string GetSaveSlotSessionSeedLabel(int slot)
		{
			return _saveSlotCache[slot].SessionSeedLabel;
		}

		public static string GetSaveSlotDateTimeLabel(int slot)
		{
			return _saveSlotCache[slot].DateTimeLabel;
		}

		public static string GetOverlaySeedStatus()
		{
			try
			{
				ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
				if (activeExpedition != null)
				{
					return "Current seed: " + activeExpedition.SessionSeed;
				}
			}
			catch (Exception ex)
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					((BasePlugin)instance).Log.LogDebug((object)("Save-slot overlay: current SessionSeed unavailable: " + ex.Message));
				}
			}
			if (_f8Armed && _forcingSeedKnown)
			{
				return "Currently forcing seed: " + _forcingSeed;
			}
			return string.Empty;
		}

		public static void Postfix()
		{
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				if (Input.GetKeyDown((KeyCode)286))
				{
					SaveWithF5();
					RefreshSaveSlotCache();
				}
				if (Input.GetKey((KeyCode)96))
				{
					if (Input.GetKeyDown((KeyCode)276))
					{
						ChangeSelectedSaveSlot(-1);
					}
					else if (Input.GetKeyDown((KeyCode)275))
					{
						ChangeSelectedSaveSlot(1);
					}
				}
				if (Input.GetKeyDown((KeyCode)289))
				{
					_f8SaveSlot = _selectedSaveSlot;
					if (!TryReadSavedMetadataFromPath(GetCheckpointSavePath(_f8SaveSlot), out var saved) || !saved.HasSeeds)
					{
						_f8Armed = false;
						GuiBehaviour.ShowTemporary("(F8) No valid save with seeds", 3f);
					}
					else
					{
						_f8Armed = true;
						_f8AppliedThisSelection = false;
						string text = saved.LevelId ?? "unknown (v2)";
						GuiBehaviour.ShowTemporary("(F8) Forcing level generation for level: " + text, 10f);
						Plugin instance = Plugin.Instance;
						if (instance != null)
						{
							ManualLogSource log = ((BasePlugin)instance).Log;
							BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(45, 1, ref flag);
							if (flag)
							{
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F8 armed for saved level '");
								((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
								((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (read from disk).");
							}
							log.LogInfo(val);
						}
					}
					RefreshSaveSlotCache();
				}
				if (Input.GetKeyDown((KeyCode)290))
				{
					LoadSoloWithF9();
				}
				if (Input.GetKeyDown((KeyCode)291))
				{
					LoadMultiplayerWithF10();
				}
			}
			catch (Exception ex)
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log2 = ((BasePlugin)instance).Log;
					BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Hotkey operation failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
					}
					log2.LogError(val2);
				}
			}
		}

		private static void SaveWithF5()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			if (!IsInLevel())
			{
				GuiBehaviour.ShowTemporary("(F5) Only available in level", 2f);
				return;
			}
			if (!IsHost())
			{
				GuiBehaviour.ShowTemporary("(F5) Host only", 2f);
				return;
			}
			CaptureCheckpointBuffer();
			BuildCheckpointClone();
			SaveCheckpointToDisk();
			if (HasLoadedCheckpoint())
			{
				GuiBehaviour.ShowTemporary("(F5) Game saved", 2f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(30, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F5: checkpoint saved to slot ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_selectedSaveSlot + 1);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
			}
			else
			{
				GuiBehaviour.ShowTemporary("(F5) Save failed", 2f);
			}
		}

		private static bool TryExtractLevelId(string value, out string levelId)
		{
			levelId = null;
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			Match match = Regex.Match(value.Trim().ToUpperInvariant(), "(?<![A-Z0-9])R\\d+[A-E]\\d+(?![A-Z0-9])");
			if (!match.Success)
			{
				return false;
			}
			levelId = match.Value;
			return true;
		}

		private static bool TryGetCurrentLevelId(out string levelId)
		{
			levelId = null;
			try
			{
				return TryExtractLevelId(RundownManager.ActiveExpeditionHeader, out levelId);
			}
			catch
			{
				return false;
			}
		}

		private static bool ValidateSavedLevel(SavedMetadata saved)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Expected O, but got Unknown
			if (string.IsNullOrEmpty(saved.LevelId))
			{
				return true;
			}
			bool flag = default(bool);
			if (!TryGetCurrentLevelId(out var levelId))
			{
				GuiBehaviour.ShowTemporary("(Load) Could not identify current GTFO level", 3f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(70, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Saved level is '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(saved.LevelId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("', but the current GTFO level could not be identified.");
					}
					log.LogWarning(val);
				}
				return false;
			}
			if (!string.Equals(levelId, saved.LevelId, StringComparison.OrdinalIgnoreCase))
			{
				GuiBehaviour.ShowTemporary("(Load) Wrong level. Save: " + saved.LevelId + ", Current: " + levelId, 4f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log2 = ((BasePlugin)instance).Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(43, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint level mismatch. Save=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(saved.LevelId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Current=");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(levelId);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log2.LogWarning(val);
				}
				return false;
			}
			return true;
		}

		private static bool ValidateSavedSessionSeed(SavedMetadata saved)
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Expected O, but got Unknown
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			if (!saved.HasSeeds)
			{
				GuiBehaviour.ShowTemporary("(Load) Save has no SessionSeed", 3f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					((BasePlugin)instance).Log.LogWarning((object)"Checkpoint SessionSeed validation failed: save has no stored generation seeds.");
				}
				return false;
			}
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			if (activeExpedition == null)
			{
				GuiBehaviour.ShowTemporary("(Load) Expedition unavailable", 3f);
				Plugin instance2 = Plugin.Instance;
				if (instance2 != null)
				{
					((BasePlugin)instance2).Log.LogWarning((object)"Checkpoint SessionSeed validation failed: no active expedition.");
				}
				return false;
			}
			int sessionSeed = activeExpedition.SessionSeed;
			Plugin instance3 = Plugin.Instance;
			bool flag = default(bool);
			if (instance3 != null)
			{
				ManualLogSource log = ((BasePlugin)instance3).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint SessionSeed validation: saved=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(saved.SessionSeed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", current=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(sessionSeed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
			if (sessionSeed != saved.SessionSeed)
			{
				GuiBehaviour.ShowTemporary($"(Load) SessionSeed mismatch. Save: {saved.SessionSeed}, Current: {sessionSeed}", 4f);
				instance3 = Plugin.Instance;
				if (instance3 != null)
				{
					ManualLogSource log2 = ((BasePlugin)instance3).Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(63, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Checkpoint SessionSeed mismatch. Save=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(saved.SessionSeed);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(", Current=");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(sessionSeed);
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(". Load refused.");
					}
					log2.LogWarning(val2);
				}
				return false;
			}
			instance3 = Plugin.Instance;
			if (instance3 != null)
			{
				ManualLogSource log3 = ((BasePlugin)instance3).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint SessionSeed matched: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(saved.SessionSeed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log3.LogInfo(val);
			}
			return true;
		}

		private static void LoadSoloWithF9()
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			SavedMetadata saved;
			if (!IsInLevel())
			{
				GuiBehaviour.ShowTemporary("(F9) Only available in level", 2f);
			}
			else if (!IsHost())
			{
				GuiBehaviour.ShowTemporary("(F9) Host only", 2f);
			}
			else if (!LoadCheckpointFromDisk(out saved))
			{
				GuiBehaviour.ShowTemporary("(F9) No savegame found", 2f);
			}
			else
			{
				if (!ValidateSavedLevel(saved) || !ValidateSavedSessionSeed(saved))
				{
					return;
				}
				InstallCloneAndRecall();
				CaptureCheckpointBuffer();
				GuiBehaviour.ShowTemporary("(F9) Game loaded (solo)", 2f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F9: checkpoint loaded from slot ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_selectedSaveSlot + 1);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					}
					log.LogInfo(val);
				}
			}
		}

		private static void LoadMultiplayerWithF10()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Expected O, but got Unknown
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Expected O, but got Unknown
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Expected O, but got Unknown
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_040e: Expected O, but got Unknown
			//IL_0445: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Expected O, but got Unknown
			//IL_04ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d1: Expected O, but got Unknown
			//IL_0508: Unknown result type (might be due to invalid IL or missing references)
			//IL_050f: Expected O, but got Unknown
			//IL_054b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0552: Expected O, but got Unknown
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_059f: Expected O, but got Unknown
			Plugin instance = Plugin.Instance;
			bool flag = default(bool);
			if (instance != null)
			{
				ManualLogSource log = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(7, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": BEGIN");
				}
				log.LogInfo(val);
			}
			if (!IsInLevel())
			{
				GuiBehaviour.ShowTemporary("(F10) Only available in level", 2f);
				return;
			}
			if (!IsHost())
			{
				GuiBehaviour.ShowTemporary("(F10) Host only", 2f);
				return;
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log2 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": before CaptureCheckpointBuffer");
				}
				log2.LogInfo(val);
			}
			CaptureCheckpointBuffer();
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log3 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": after CaptureCheckpointBuffer");
				}
				log3.LogInfo(val);
			}
			SNet_Capture capture = GetCapture();
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log4 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(20, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": capture=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)capture == (Object)null) ? "NULL" : "OK");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", buffers=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((((capture != null) ? capture.m_buffers : null) == null) ? "NULL" : ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)capture.m_buffers).Length.ToString());
				}
				log4.LogInfo(val);
			}
			SNet_CaptureBuffer liveCheckpoint = GetLiveCheckpoint(capture);
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log5 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(19, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": nativeCheckpoint=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((liveCheckpoint == null) ? "NULL" : $"OK valid={liveCheckpoint.isValid} type={liveCheckpoint.type}");
				}
				log5.LogInfo(val);
			}
			if (liveCheckpoint == null)
			{
				GuiBehaviour.ShowTemporary("(F10) Cannot load save - Try pressing F9 first", 2f);
				instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log6 = ((BasePlugin)instance).Log;
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("F10");
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": native checkpoint is NULL; aborting F10.");
					}
					log6.LogWarning(val2);
				}
				return;
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log7 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(31, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": before LoadCheckpointFromDisk");
				}
				log7.LogInfo(val);
			}
			if (!LoadCheckpointFromDisk(out var saved))
			{
				GuiBehaviour.ShowTemporary("(F10) No savegame found", 2f);
				return;
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log8 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": disk save loaded level=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(saved.LevelId ?? "null");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", hasSeeds=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(saved.HasSeeds);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", clone=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((_clonedCheckpoint == null) ? "NULL" : "OK");
				}
				log8.LogInfo(val);
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log9 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": before ValidateSavedLevel");
				}
				log9.LogInfo(val);
			}
			if (!ValidateSavedLevel(saved))
			{
				return;
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log10 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": after ValidateSavedLevel");
				}
				log10.LogInfo(val);
			}
			if (!ValidateSavedSessionSeed(saved))
			{
				return;
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log11 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(32, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": after ValidateSavedSessionSeed");
				}
				log11.LogInfo(val);
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log12 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": before ReplaceCheckpointContents target=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((liveCheckpoint == null) ? "NULL" : "OK");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" source=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((_clonedCheckpoint == null) ? "NULL" : "OK");
				}
				log12.LogInfo(val);
			}
			ReplaceCheckpointContents(liveCheckpoint, _clonedCheckpoint);
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log13 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": after ReplaceCheckpointContents");
				}
				log13.LogInfo(val);
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log14 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": before TryEndPlayingViaGS");
				}
				log14.LogInfo(val);
			}
			TryEndPlayingViaGS();
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log15 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("F10");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": after TryEndPlayingViaGS");
				}
				log15.LogInfo(val);
			}
			GuiBehaviour.ShowTemporary("(F10) Ready to load checkpoint (multiplayer)", 3f);
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log16 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F10: multiplayer checkpoint prepared from slot ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_selectedSaveSlot + 1);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log16.LogInfo(val);
			}
		}

		public static void ExecuteQueuedF8()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			try
			{
				if (_f8Armed && !_f8AppliedThisSelection)
				{
					_f8AppliedThisSelection = true;
					_f8Armed = false;
					ApplySavedExpeditionSeeds();
				}
			}
			catch (Exception ex)
			{
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(21, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F8 execution failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogError(val);
				}
				GuiBehaviour.ShowTemporary("(F8) Failed - see log", 3f);
			}
		}

		private static void ApplySavedExpeditionSeeds()
		{
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Expected O, but got Unknown
			if (!IsHost())
			{
				GuiBehaviour.ShowTemporary("(F8) Host only", 2f);
				return;
			}
			if (!TryReadSavedMetadataFromPath(GetCheckpointSavePath(_f8SaveSlot), out var saved) || !saved.HasSeeds)
			{
				GuiBehaviour.ShowTemporary("(F8) Selected save has no usable seeds", 3f);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					((BasePlugin)instance).Log.LogWarning((object)"F8: checkpoint.dat missing, invalid, or has no seeds.");
				}
				return;
			}
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			if (activeExpedition == null)
			{
				GuiBehaviour.ShowTemporary("(F8) No active expedition", 2f);
				return;
			}
			if (!ValidateSavedLevel(saved))
			{
				Plugin instance2 = Plugin.Instance;
				if (instance2 != null)
				{
					((BasePlugin)instance2).Log.LogWarning((object)"F8: saved checkpoint belongs to a different level.");
				}
				return;
			}
			activeExpedition.SetSeeds(saved.HostIDSeed, saved.SessionSeed);
			pActiveExpedition activeExpeditionData = RundownManager.GetActiveExpeditionData();
			activeExpeditionData.hostIDSeed = saved.HostIDSeed;
			activeExpeditionData.sessionSeed = saved.SessionSeed;
			RundownManager current = RundownManager.Current;
			if ((Object)(object)current == (Object)null)
			{
				throw new InvalidOperationException("RundownManager.Current is null.");
			}
			current.SetActiveExpeditionData(activeExpeditionData);
			RefreshSyncManagerLevelChecksum();
			GuiBehaviour.ShowTemporary("(F8) Seeds applied successfully", 3f);
			Plugin instance3 = Plugin.Instance;
			if (instance3 != null)
			{
				ManualLogSource log = ((BasePlugin)instance3).Log;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F8: saved expedition seeds applied from slot ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_f8SaveSlot + 1);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": H=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(saved.HostIDSeed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" S=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(saved.SessionSeed);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				log.LogInfo(val);
			}
		}

		private static void RefreshSyncManagerLevelChecksum()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			if (!IsHost())
			{
				return;
			}
			ExpeditionInTierData activeExpedition = RundownManager.ActiveExpedition;
			if (activeExpedition == null)
			{
				return;
			}
			uint checksum;
			bool flag = default(bool);
			Plugin instance;
			try
			{
				checksum = activeExpedition.GetChecksum();
			}
			catch (Exception ex)
			{
				instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("F8: failed to recreate checksum: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
				return;
			}
			Il2CppArrayBase<SNet_SyncManager> val2 = Object.FindObjectsOfType<SNet_SyncManager>();
			if (val2 == null)
			{
				return;
			}
			foreach (SNet_SyncManager item in val2)
			{
				if ((Object)(object)item != (Object)null)
				{
					item.SetLevelChecksum(checksum);
				}
			}
			instance = Plugin.Instance;
			if (instance != null)
			{
				ManualLogSource log2 = ((BasePlugin)instance).Log;
				BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("F8: refreshed checksum to ");
					((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<uint>(checksum);
					((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
				}
				log2.LogInfo(val3);
			}
		}

		private static SNet_Capture GetCapture()
		{
			Il2CppArrayBase<SNet_Capture> val = Object.FindObjectsOfType<SNet_Capture>();
			if (val == null || val.Length <= 0)
			{
				return null;
			}
			return val[0];
		}

		private static bool IsHost()
		{
			return SNet.IsMaster;
		}

		private static bool IsInLevel()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			return (int)GameStateManager.CurrentStateName == 10;
		}

		private static SNet_CaptureBuffer GetLiveCheckpoint(SNet_Capture capture)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			if (((capture != null) ? capture.m_buffers : null) == null)
			{
				return null;
			}
			foreach (SNet_CaptureBuffer item in (Il2CppArrayBase<SNet_CaptureBuffer>)(object)capture.m_buffers)
			{
				if (item != null && (int)item.type == 3)
				{
					return item;
				}
			}
			return null;
		}

		private static void CaptureCheckpointBuffer()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			Plugin instance = Plugin.Instance;
			if (instance != null)
			{
				((BasePlugin)instance).Log.LogInfo((object)"Checkpoint capture: BEGIN");
			}
			if (!IsHost())
			{
				return;
			}
			SNet_Capture capture = GetCapture();
			Plugin instance2 = Plugin.Instance;
			bool flag = default(bool);
			if (instance2 != null)
			{
				ManualLogSource log = ((BasePlugin)instance2).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint capture: SNet_Capture=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)(object)capture == (Object)null) ? "NULL" : "OK");
				}
				log.LogInfo(val);
			}
			if ((Object)(object)capture == (Object)null)
			{
				throw new InvalidOperationException("No SNet_Capture found.");
			}
			instance2 = Plugin.Instance;
			if (instance2 != null)
			{
				ManualLogSource log2 = ((BasePlugin)instance2).Log;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(28, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint capture: buffers=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((capture.m_buffers == null) ? "NULL" : ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)capture.m_buffers).Length.ToString());
				}
				log2.LogInfo(val);
			}
			capture.CaptureGameState((eBufferType)3);
			Plugin instance3 = Plugin.Instance;
			if (instance3 != null)
			{
				((BasePlugin)instance3).Log.LogInfo((object)"Checkpoint capture: CaptureGameState returned");
			}
			_clonedCheckpoint = null;
		}

		private static void BuildCheckpointClone()
		{
			//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_002f: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (!IsHost())
			{
				return;
			}
			SNet_CaptureBuffer liveCheckpoint = GetLiveCheckpoint(GetCapture());
			if (liveCheckpoint == null || !liveCheckpoint.isValid || liveCheckpoint.m_passes == null)
			{
				return;
			}
			SNet_CaptureBuffer val = new SNet_CaptureBuffer((eBufferType)3)
			{
				type = liveCheckpoint.type,
				data = liveCheckpoint.data
			};
			Il2CppReferenceArray<List<Il2CppStructArray<byte>>> val2 = new Il2CppReferenceArray<List<Il2CppStructArray<byte>>>((long)((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)liveCheckpoint.m_passes).Length);
			for (int i = 0; i < ((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)liveCheckpoint.m_passes).Length; i++)
			{
				List<Il2CppStructArray<byte>> val3 = ((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)liveCheckpoint.m_passes)[i];
				List<Il2CppStructArray<byte>> val4 = new List<Il2CppStructArray<byte>>();
				if (val3 != null)
				{
					for (int j = 0; j < val3.Count; j++)
					{
						Il2CppStructArray<byte> val5 = val3[j];
						if (val5 != null)
						{
							val4.Add(CopyByteArray(val5));
						}
					}
				}
				((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)val2)[i] = val4;
			}
			val.m_passes = val2;
			val.isValid = true;
			_clonedCheckpoint = val;
		}

		private static void TryEndPlayingViaGS()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (IsHost() && GameStateManager.CurrentState != null && IsInLevel())
			{
				new GS_InLevel(((Il2CppObjectBase)GameStateManager.CurrentState).Pointer).TryEndPlaying(GS_InLevel.FAIL_COMMAND_CODE);
			}
		}

		private static void ReplaceCheckpointContents(SNet_CaptureBuffer target, SNet_CaptureBuffer source)
		{
			if (IsHost() && target != null && source != null && source.isValid && source.m_passes != null)
			{
				target.m_passes = source.m_passes;
			}
		}

		private static void InstallCloneAndRecall()
		{
			if (IsHost() && HasLoadedCheckpoint())
			{
				SNet_Capture capture = GetCapture();
				if (((capture != null) ? capture.m_buffers : null) != null && ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)capture.m_buffers).Length > 3)
				{
					((Il2CppArrayBase<SNet_CaptureBuffer>)(object)capture.m_buffers)[3] = _clonedCheckpoint;
					capture.RecallGameState((eBufferType)3);
				}
			}
		}

		private static void SaveCheckpointToDisk()
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected I4, but got Unknown
			//IL_00f1: 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_00fa: 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_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if (!IsHost() || !HasLoadedCheckpoint())
			{
				return;
			}
			SeedRandom buildSeedRandom = Builder.BuildSeedRandom;
			SeedRandom hostIDSeedRandom = Builder.HostIDSeedRandom;
			SeedRandom sessionSeedRandom = Builder.SessionSeedRandom;
			if (buildSeedRandom == null || hostIDSeedRandom == null || sessionSeedRandom == null)
			{
				throw new InvalidOperationException("GTFO generation seeds are unavailable.");
			}
			if (!TryGetCurrentLevelId(out var levelId))
			{
				throw new InvalidOperationException("Could not identify the current GTFO level.");
			}
			string directoryName = Path.GetDirectoryName(GetSelectedCheckpointSavePath());
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			using FileStream output = new FileStream(GetSelectedCheckpointSavePath(), FileMode.Create, FileAccess.Write, FileShare.None);
			using BinaryWriter binaryWriter = new BinaryWriter(output, Encoding.UTF8);
			binaryWriter.Write("GTFOCP");
			binaryWriter.Write(4);
			binaryWriter.Write(levelId);
			binaryWriter.Write(DateTime.Now.ToBinary());
			binaryWriter.Write(buildSeedRandom.Seed);
			binaryWriter.Write(hostIDSeedRandom.Seed);
			binaryWriter.Write(sessionSeedRandom.Seed);
			binaryWriter.Write((byte)(int)_clonedCheckpoint.type);
			pBufferData data = _clonedCheckpoint.data;
			binaryWriter.Write(data.sendingPlayerLookup);
			binaryWriter.Write(data.levelChecksum);
			binaryWriter.Write(data.bufferID);
			binaryWriter.Write(data.progressionTime);
			binaryWriter.Write(data.recallCount);
			binaryWriter.Write(((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)_clonedCheckpoint.m_passes).Length);
			foreach (List<Il2CppStructArray<byte>> item in (Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)_clonedCheckpoint.m_passes)
			{
				if (item == null)
				{
					binaryWriter.Write(-1);
					continue;
				}
				binaryWriter.Write(item.Count);
				for (int i = 0; i < item.Count; i++)
				{
					Il2CppStructArray<byte> val = item[i];
					if (val == null)
					{
						binaryWriter.Write(-1);
						continue;
					}
					binaryWriter.Write(((Il2CppArrayBase<byte>)(object)val).Length);
					for (int j = 0; j < ((Il2CppArrayBase<byte>)(object)val).Length; j++)
					{
						binaryWriter.Write(((Il2CppArrayBase<byte>)(object)val)[j]);
					}
				}
			}
		}

		private static bool LoadCheckpointFromDisk(out SavedMetadata saved)
		{
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			saved = default(SavedMetadata);
			_clonedCheckpoint = null;
			if (!IsHost() || !File.Exists(GetSelectedCheckpointSavePath()))
			{
				return false;
			}
			using (FileStream input = new FileStream(GetSelectedCheckpointSavePath(), FileMode.Open, FileAccess.Read, FileShare.Read))
			{
				using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
				if (binaryReader.ReadString() != "GTFOCP")
				{
					throw new InvalidDataException("Invalid checkpoint file.");
				}
				int num = binaryReader.ReadInt32();
				switch (num)
				{
				case 3:
				case 4:
				{
					string text = binaryReader.ReadString();
					if (!Regex.IsMatch(text ?? "", "^R\\d+[A-E]\\d+$"))
					{
						throw new InvalidDataException("Invalid saved GTFO level ID: '" + text + "'.");
					}
					saved.LevelId = text;
					if (num == 4)
					{
						saved.SaveDateTime = DateTime.FromBinary(binaryReader.ReadInt64());
						saved.HasSaveDateTime = true;
					}
					saved.HasSeeds = true;
					binaryReader.ReadInt32();
					saved.HostIDSeed = binaryReader.ReadInt32();
					saved.SessionSeed = binaryReader.ReadInt32();
					break;
				}
				case 2:
					saved.HasSeeds = true;
					binaryReader.ReadInt32();
					saved.HostIDSeed = binaryReader.ReadInt32();
					saved.SessionSeed = binaryReader.ReadInt32();
					break;
				case 1:
				{
					Plugin instance = Plugin.Instance;
					if (instance != null)
					{
						((BasePlugin)instance).Log.LogInfo((object)"Loaded v1 checkpoint: generation seeds are unavailable; F8 is disabled for this save.");
					}
					break;
				}
				default:
					throw new InvalidDataException($"Unsupported checkpoint file version: {num}.");
				}
				eBufferType val = (eBufferType)binaryReader.ReadByte();
				SNet_CaptureBuffer val2 = new SNet_CaptureBuffer(val);
				val2.data = new pBufferData
				{
					sendingPlayerLookup = binaryReader.ReadUInt64(),
					levelChecksum = binaryReader.ReadUInt64(),
					bufferID = binaryReader.ReadUInt16(),
					progressionTime = binaryReader.ReadSingle(),
					recallCount = binaryReader.ReadUInt64()
				};
				val2.type = val;
				int num2 = binaryReader.ReadInt32();
				if (num2 < 0 || num2 > 100)
				{
					throw new InvalidDataException("Invalid pass count.");
				}
				Il2CppReferenceArray<List<Il2CppStructArray<byte>>> val3 = new Il2CppReferenceArray<List<Il2CppStructArray<byte>>>((long)num2);
				for (int i = 0; i < num2; i++)
				{
					int num3 = binaryReader.ReadInt32();
					if (num3 < 0)
					{
						((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)val3)[i] = new List<Il2CppStructArray<byte>>();
						continue;
					}
					if (num3 > 100000)
					{
						throw new InvalidDataException("Invalid chunk count.");
					}
					List<Il2CppStructArray<byte>> val4 = new List<Il2CppStructArray<byte>>();
					for (int j = 0; j < num3; j++)
					{
						int num4 = binaryReader.ReadInt32();
						if (num4 >= 0)
						{
							if (num4 > 104857600)
							{
								throw new InvalidDataException("Invalid chunk length.");
							}
							Il2CppStructArray<byte> val5 = new Il2CppStructArray<byte>((long)num4);
							for (int k = 0; k < num4; k++)
							{
								((Il2CppArrayBase<byte>)(object)val5)[k] = binaryReader.ReadByte();
							}
							val4.Add(val5);
						}
					}
					((Il2CppArrayBase<List<Il2CppStructArray<byte>>>)(object)val3)[i] = val4;
				}
				val2.m_passes = val3;
				val2.isValid = true;
				_clonedCheckpoint = val2;
			}
			return true;
		}

		private static Il2CppStructArray<byte> CopyByteArray(Il2CppStructArray<byte> source)
		{
			if (source == null)
			{
				return null;
			}
			Il2CppStructArray<byte> val = new Il2CppStructArray<byte>((long)((Il2CppArrayBase<byte>)(object)source).Length);
			for (int i = 0; i < ((Il2CppArrayBase<byte>)(object)source).Length; i++)
			{
				((Il2CppArrayBase<byte>)(object)val)[i] = ((Il2CppArrayBase<byte>)(object)source)[i];
			}
			return val;
		}

		private static bool TryReadSavedMetadataFromPath(string path, out SavedMetadata saved)
		{
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Expected O, but got Unknown
			saved = default(SavedMetadata);
			try
			{
				if (!File.Exists(path))
				{
					return false;
				}
				using FileStream input = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
				using BinaryReader binaryReader = new BinaryReader(input, Encoding.UTF8);
				if (binaryReader.ReadString() != "GTFOCP")
				{
					throw new InvalidDataException("Invalid checkpoint file signature.");
				}
				int num = binaryReader.ReadInt32();
				switch (num)
				{
				case 3:
				case 4:
					saved.LevelId = binaryReader.ReadString();
					if (!Regex.IsMatch(saved.LevelId ?? "", "^R\\d+[A-E]\\d+$"))
					{
						throw new InvalidDataException("Invalid saved level ID.");
					}
					if (num == 4)
					{
						saved.SaveDateTime = DateTime.FromBinary(binaryReader.ReadInt64());
						saved.HasSaveDateTime = true;
					}
					break;
				default:
					throw new InvalidDataException($"Unsupported checkpoint version: {num}.");
				case 1:
				case 2:
					break;
				}
				if (num == 2 || num == 3 || num == 4)
				{
					binaryReader.ReadInt32();
					saved.HostIDSeed = binaryReader.ReadInt32();
					saved.SessionSeed = binaryReader.ReadInt32();
					saved.HasSeeds = true;
				}
				binaryReader.ReadByte();
				binaryReader.ReadUInt64();
				binaryReader.ReadUInt64();
				return true;
			}
			catch (Exception ex)
			{
				saved = default(SavedMetadata);
				Plugin instance = Plugin.Instance;
				if (instance != null)
				{
					ManualLogSource log = ((BasePlugin)instance).Log;
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(33, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint metadata read failed: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
					}
					log.LogWarning(val);
				}
				return false;
			}
		}

		private static bool HasLoadedCheckpoint()
		{
			if (_clonedCheckpoint != null && _clonedCheckpoint.isValid)
			{
				return _clonedCheckpoint.m_passes != null;
			}
			return false;
		}
	}
}