Decompiled source of gtfo quicksave v1.1.1

GTFO-quicksave.dll

Decompiled 2 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using Agents;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using ChainedPuzzles;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("GTFO-quicksave")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+7d910e0309938b0859ed6938912f194e84c63a80")]
[assembly: AssemblyProduct("GTFO-quicksave")]
[assembly: AssemblyTitle("GTFO-quicksave")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace GTFOQuicksave
{
	internal static class ClearedScanHider
	{
		private const float HideWindow = 4f;

		private static float _remaining;

		private static bool _loggedError;

		public static void Schedule()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			_remaining = 4f;
			_loggedError = false;
			int num = Hide();
			if (num > 0)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Hid ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" cleared security scans");
				}
				logSource.LogInfo(val);
			}
		}

		public static void Tick()
		{
			if (!(_remaining <= 0f))
			{
				_remaining -= Time.unscaledDeltaTime;
				Hide();
			}
		}

		private static int Hide()
		{
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			ChainedPuzzleManager current = ChainedPuzzleManager.Current;
			List<ChainedPuzzleInstance> val = ((current != null) ? current.m_instances : null);
			if (val == null)
			{
				return 0;
			}
			int num = 0;
			bool flag = default(bool);
			for (int i = 0; i < val.Count; i++)
			{
				ChainedPuzzleInstance val2 = val[i];
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				try
				{
					int num2 = val2.NRofPuzzles();
					for (int j = 0; j < num2; j++)
					{
						num += HideCore(val2.GetPuzzle(j), val2.IsSolved);
					}
				}
				catch (Exception ex)
				{
					if (!_loggedError)
					{
						_loggedError = true;
						ManualLogSource logSource = Plugin.LogSource;
						BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Cleared scan hide failed: ");
							((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
						}
						logSource.LogError(val3);
					}
				}
			}
			return num;
		}

		private static int HideCore(iChainedPuzzleCore? core, bool solved)
		{
			if (core == null)
			{
				return 0;
			}
			CP_Cluster_Core val = ((Il2CppObjectBase)core).TryCast<CP_Cluster_Core>();
			if ((Object)(object)val != (Object)null)
			{
				bool flag = solved || (val.m_sync != null && val.IsFinished());
				int num = 0;
				if (flag)
				{
					iChainedPuzzleHolopathSpline spline = val.m_spline;
					if (spline != null)
					{
						spline.SetVisible(false);
					}
					iChainedPuzzleHUD hud = val.m_hud;
					if (hud != null)
					{
						hud.SetVisible(val.m_puzzleIndex, false);
					}
					num++;
				}
				Il2CppReferenceArray<iChainedPuzzleCore> childCores = val.m_childCores;
				if (childCores == null)
				{
					return num;
				}
				for (int i = 0; i < ((Il2CppArrayBase<iChainedPuzzleCore>)(object)childCores).Length; i++)
				{
					num += HideCore(((Il2CppArrayBase<iChainedPuzzleCore>)(object)childCores)[i], flag);
				}
				return num;
			}
			CP_Bioscan_Core val2 = ((Il2CppObjectBase)core).TryCast<CP_Bioscan_Core>();
			if ((Object)(object)val2 == (Object)null || (!solved && (val2.m_sync == null || !val2.IsFinished())))
			{
				return 0;
			}
			iChainedPuzzleBioscanGraphics graphics = val2.m_graphics;
			if (graphics != null)
			{
				graphics.SetVisible(false, false);
			}
			iChainedPuzzleHolopathSpline spline2 = val2.m_spline;
			if (spline2 != null)
			{
				spline2.SetVisible(false);
			}
			iChainedPuzzleScanner playerScanner = val2.m_playerScanner;
			if (playerScanner != null)
			{
				playerScanner.StopScan();
			}
			iChainedPuzzleHUD hud2 = val2.m_hud;
			if (hud2 != null)
			{
				hud2.SetVisible(val2.m_puzzleIndex, false);
			}
			return 1;
		}
	}
	[BepInPlugin("levi.gtfo-quicksave", "GTFO Quicksave", "1.0.0")]
	public class Plugin : BasePlugin
	{
		internal static ManualLogSource LogSource;

		public override void Load()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			LogSource = ((BasePlugin)this).Log;
			if (!ClassInjector.IsTypeRegisteredInIl2Cpp<QuicksaveBehaviour>())
			{
				ClassInjector.RegisterTypeInIl2Cpp<QuicksaveBehaviour>();
			}
			((BasePlugin)this).AddComponent<QuicksaveBehaviour>();
			new Harmony("levi.gtfo-quicksave").PatchAll();
			((BasePlugin)this).Log.LogInfo((object)"Host double-taps F5 to save a checkpoint and presses F9 three times to load it.");
		}
	}
	public class QuicksaveBehaviour : MonoBehaviour
	{
		public const float DoublePressWindow = 1f;

		private const float CaptureTimeout = 5f;

		private const float WipeDamage = 1000f;

		private const int LoadPressesRequired = 3;

		private float _saveArmedAt;

		private float _loadArmedAt;

		private int _loadPresses;

		private bool _capturePending;

		private float _captureStartedAt;

		private Vector3 _pendingPosition;

		private bool _hadBuffer;

		private int _bufferIdBefore;

		private bool _sawCapturing;

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

		public void Update()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			if ((Object)(object)SNet.Current == (Object)null || !SNet.IsMaster || (Object)(object)GameStateManager.Current == (Object)null)
			{
				return;
			}
			if (_capturePending && (int)GameStateManager.CurrentStateName == 10)
			{
				PumpCapture();
			}
			if ((int)GameStateManager.CurrentStateName != 10 || CheckpointManager.IsReloadingCheckpoint)
			{
				_saveArmedAt = 0f;
				_loadArmedAt = 0f;
				_loadPresses = 0;
				_capturePending = false;
				return;
			}
			ClearedScanHider.Tick();
			if (PlayerManager.HasLocalPlayerAgent())
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (Input.GetKeyDown((KeyCode)286))
				{
					OnDoublePress(ref _saveArmedAt, realtimeSinceStartup, "Press F5 again to save", Save);
				}
				else if (Input.GetKeyDown((KeyCode)290))
				{
					OnLoadPress(realtimeSinceStartup);
				}
			}
		}

		private void OnDoublePress(ref float armedAt, float now, string armMessage, Action commit)
		{
			if (armedAt > 0f && now - armedAt <= 1f)
			{
				armedAt = 0f;
				commit();
			}
			else
			{
				armedAt = now;
				Notify(armMessage);
			}
		}

		private void OnLoadPress(float now)
		{
			if (_loadArmedAt <= 0f || now - _loadArmedAt > 1f)
			{
				_loadPresses = 0;
			}
			_loadPresses++;
			_loadArmedAt = now;
			if (_loadPresses < 3)
			{
				int num = 3 - _loadPresses;
				Notify((num == 1) ? "Press F9 once more to load" : "Press F9 twice more to load");
			}
			else
			{
				_loadPresses = 0;
				_loadArmedAt = 0f;
				Load();
			}
		}

		private void Save()
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (_capturePending)
			{
				Notify("Checkpoint is busy");
				return;
			}
			SNet_Capture capture = SNet.Capture;
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			if ((Object)(object)capture == (Object)null || (Object)(object)localPlayerAgent == (Object)null || capture.IsCapturing || capture.IsRecalling)
			{
				Notify("Checkpoint is busy");
				return;
			}
			_pendingPosition = ((Agent)localPlayerAgent).Position;
			try
			{
				MapDataManager.CheckpointStoreSyncedGUIObjects();
				RememberBuffer();
				capture.CaptureGameState((eBufferType)3);
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint capture failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
				}
				logSource.LogError(val);
				Notify("Checkpoint capture failed");
				return;
			}
			_capturePending = true;
			_sawCapturing = capture.IsCapturing;
			_captureStartedAt = Time.realtimeSinceStartup;
			PumpCapture();
		}

		private void Load()
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			if (_capturePending || !QuicksaveState.HasCheckpoint || !HasValidCheckpointBuffer())
			{
				Notify(_capturePending ? "Checkpoint is busy" : "No checkpoint to load");
				return;
			}
			List<PlayerAgent> playerAgentsInLevel = PlayerManager.PlayerAgentsInLevel;
			if (playerAgentsInLevel == null || playerAgentsInLevel.Count == 0)
			{
				Notify("Checkpoint load failed");
				return;
			}
			try
			{
				bool flag = false;
				for (int i = 0; i < playerAgentsInLevel.Count; i++)
				{
					PlayerAgent val = playerAgentsInLevel[i];
					if (!((Object)(object)val == (Object)null) && ((Agent)val).Alive && !((Object)(object)val.Damage == (Object)null))
					{
						((Dam_SyncedDamageBase)val.Damage).FallDamage(1000f);
						if (((Agent)val).Alive)
						{
							((Dam_SyncedDamageBase)val.Damage).FallDamage(1000f);
						}
						flag = true;
					}
				}
				if (!flag)
				{
					Notify("Checkpoint load failed");
					return;
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag2 = default(bool);
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag2);
				if (flag2)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Checkpoint load failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				logSource.LogError(val2);
				Notify("Checkpoint load failed");
				return;
			}
			Notify("Loading checkpoint");
		}

		private void PumpCapture()
		{
			//IL_005b: 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_0086: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			SNet_Capture capture = SNet.Capture;
			if ((Object)(object)capture == (Object)null)
			{
				FailCapture();
				return;
			}
			if (!IsCaptureReady(capture))
			{
				if (Time.realtimeSinceStartup - _captureStartedAt > 5f)
				{
					FailCapture();
				}
				return;
			}
			_capturePending = false;
			CheckpointManager.StoreCheckpoint(_pendingPosition);
			if (TryGetCheckpointBuffer(out SNet_CaptureBuffer buffer))
			{
				ManualLogSource logSource = Plugin.LogSource;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(33, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint buffer id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ushort>(buffer.data.bufferID);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" valid=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(buffer.isValid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" got=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(capture.GotBuffer((eBufferType)3));
				}
				logSource.LogInfo(val);
			}
			Notify("Checkpoint saved");
		}

		private void FailCapture()
		{
			_capturePending = false;
			LogBuffers();
			Notify("Checkpoint capture failed");
		}

		private void RememberBuffer()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			_sawCapturing = false;
			SNet_Capture capture = SNet.Capture;
			_hadBuffer = (Object)(object)capture != (Object)null && capture.GotBuffer((eBufferType)3);
			_bufferIdBefore = 0;
			if (TryGetCheckpointBuffer(out SNet_CaptureBuffer buffer) && buffer.isValid)
			{
				_bufferIdBefore = buffer.data.bufferID;
			}
		}

		private bool IsCaptureReady(SNet_Capture capture)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (capture.IsCapturing)
			{
				_sawCapturing = true;
				return false;
			}
			bool flag = capture.GotBuffer((eBufferType)3);
			int num = 0;
			if (TryGetCheckpointBuffer(out SNet_CaptureBuffer buffer) && buffer.isValid)
			{
				num = buffer.data.bufferID;
			}
			if (!flag && num == 0)
			{
				return false;
			}
			if (!_hadBuffer)
			{
				return true;
			}
			if (num != 0 && num != _bufferIdBefore)
			{
				return true;
			}
			return _sawCapturing;
		}

		private static bool HasValidCheckpointBuffer()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			SNet_Capture capture = SNet.Capture;
			if ((Object)(object)capture == (Object)null)
			{
				return false;
			}
			if (TryGetCheckpointBuffer(out SNet_CaptureBuffer buffer) && buffer.isValid && buffer.data.bufferID != 0)
			{
				return true;
			}
			return capture.GotBuffer((eBufferType)3);
		}

		private static bool TryGetCheckpointBuffer(out SNet_CaptureBuffer buffer)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			buffer = null;
			SNet_Capture capture = SNet.Capture;
			if ((Object)(object)capture == (Object)null)
			{
				return false;
			}
			Il2CppReferenceArray<SNet_CaptureBuffer> buffers = capture.m_buffers;
			if (buffers == null)
			{
				return false;
			}
			for (int i = 0; i < ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)buffers).Length; i++)
			{
				SNet_CaptureBuffer val = ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)buffers)[i];
				if (val != null && (int)val.type == 3)
				{
					buffer = val;
					return true;
				}
			}
			return false;
		}

		private static void LogBuffers()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			SNet_Capture capture = SNet.Capture;
			if ((Object)(object)capture == (Object)null)
			{
				Plugin.LogSource.LogError((object)"Checkpoint capture failed: SNet.Capture is missing.");
				return;
			}
			ManualLogSource logSource = Plugin.LogSource;
			bool flag = default(bool);
			BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(50, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Checkpoint capture failed. GotBuffer=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(capture.GotBuffer((eBufferType)3));
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" IsCapturing=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(capture.IsCapturing);
			}
			logSource.LogError(val);
			Il2CppReferenceArray<SNet_CaptureBuffer> buffers = capture.m_buffers;
			if (buffers == null)
			{
				return;
			}
			for (int i = 0; i < ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)buffers).Length; i++)
			{
				SNet_CaptureBuffer val2 = ((Il2CppArrayBase<SNet_CaptureBuffer>)(object)buffers)[i];
				if (val2 == null)
				{
					ManualLogSource logSource2 = Plugin.LogSource;
					val = new BepInExErrorLogInterpolatedStringHandler(13, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("buffer[");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] null");
					}
					logSource2.LogError(val);
					continue;
				}
				ManualLogSource logSource3 = Plugin.LogSource;
				val = new BepInExErrorLogInterpolatedStringHandler(25, 4, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("buffer[");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] type=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<eBufferType>(val2.type);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" valid=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(val2.isValid);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" id=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<ushort>(val2.data.bufferID);
				}
				logSource3.LogError(val);
			}
		}

		internal static void Notify(string message)
		{
			Plugin.LogSource.LogInfo((object)message);
			if (!((Object)(object)GuiManager.Current == (Object)null))
			{
				PlayerGuiLayer playerLayer = GuiManager.PlayerLayer;
				if (playerLayer != null && !((Object)(object)playerLayer.m_gameEventLog == (Object)null))
				{
					playerLayer.m_gameEventLog.AddLogItem(message, (eGameEventChatLogType)2);
				}
			}
		}
	}
	internal static class QuicksaveState
	{
		public static bool HasCheckpoint;
	}
	[HarmonyPatch(typeof(CheckpointManager), "StoreCheckpoint")]
	internal static class StoreCheckpointPatch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			QuicksaveState.HasCheckpoint = true;
		}
	}
	[HarmonyPatch(typeof(CheckpointManager), "OnLevelCleanup")]
	internal static class LevelCleanupPatch
	{
		[HarmonyPostfix]
		public static void Postfix()
		{
			QuicksaveState.HasCheckpoint = false;
		}
	}
	[HarmonyPatch(typeof(CheckpointManager), "OnRecallComplete")]
	internal static class RecallCompletePatch
	{
		[HarmonyPostfix]
		public static void Postfix(eBufferType bufferType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			if ((int)bufferType == 3)
			{
				ClearedScanHider.Schedule();
			}
		}
	}
}