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();
}
}
}
}