Decompiled source of DebugMod v1.10.0

DebugModPlus.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Com.LuisPedroFonseca.ProCamera2D;
using Cysharp.Threading.Tasks;
using DebugModPlus.Interop;
using DebugModPlus.Modules;
using DebugModPlus.Modules.Hitbox;
using DebugModPlus.Savestates;
using DebugModPlus.Utils;
using Febucci.UI.Core;
using HarmonyLib;
using I2.Loc;
using InputExtension;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using MonsterLove.StateMachine;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using NineSolsAPI;
using NineSolsAPI.Utils;
using PrimeTween;
using QFSW.QC;
using RCGFSM.Animation;
using RCGFSM.GameObjects;
using RCGFSM.StateEvents;
using RCGFSM.Transition;
using RCGFSM.Variable;
using RCGMaker.Core;
using TAS;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Bindings;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.Tilemaps;
using UnityEngine.UI;
using mixpanel;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DebugModPlus")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Advanced Debug Mod for Nine Sols")]
[assembly: AssemblyFileVersion("1.10.0.0")]
[assembly: AssemblyInformationalVersion("1.10.0+b1a7da59347acfda3a492b8d141c71a974dcefad")]
[assembly: AssemblyProduct("DebugModPlus")]
[assembly: AssemblyTitle("DebugModPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.10.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 TAS
{
	public static class DebugInfo
	{
		[Flags]
		public enum DebugFilter
		{
			Base = 0,
			RapidlyChanging = 1,
			Tweens = 2
		}

		private const bool ShowClipInfo = true;

		private static readonly Regex ReNumPrefix = new Regex("\\d+_");

		private static readonly Regex ReCjk = new Regex("_?\\p{IsCJKUnifiedIdeographs}+|^\\d+_");

		public static string GetInfoText(DebugFilter filter = DebugFilter.Base)
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Invalid comparison between Unknown and I4
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_052f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Unknown result type (might be due to invalid IL or missing references)
			//IL_0587: Unknown result type (might be due to invalid IL or missing references)
			//IL_058c: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0477: Unknown result type (might be due to invalid IL or missing references)
			//IL_0499: Unknown result type (might be due to invalid IL or missing references)
			//IL_04af: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			if (filter.HasFlag(DebugFilter.Tweens))
			{
				Type type = typeof(Tween).Assembly.GetType("PrimeTween.PrimeTweenManager");
				if ((object)type != null)
				{
					text += "Tweens:\n";
					foreach (object item in ReflectionExtension.GetFieldValue<IList>(type.GetField("Instance", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null), "tweens"))
					{
						text += $"- {item}\n";
					}
					text += "\n";
				}
			}
			if (!SingletonBehaviour<ApplicationCore>.IsAvailable())
			{
				return "Loading";
			}
			if (!SingletonBehaviour<GameCore>.IsAvailable())
			{
				text += "MainMenu\n";
				return text + ((object)(PlayerInputStateType)(ref SingletonBehaviour<PlayerInputBinder>.Instance.currentStateType)).ToString();
			}
			GameCore instance = SingletonBehaviour<GameCore>.Instance;
			if ((int)instance.currentCoreState != 1)
			{
				string enumName = typeof(GameCoreState).GetEnumName(instance.currentCoreState);
				text = text + enumName + "\n";
			}
			Player player = instance.player;
			if (Object.op_Implicit((Object)(object)player))
			{
				text += $"Pos: {Vector2.op_Implicit(((Component)player).transform.position)}\n";
				text += $"Speed: {((Actor)player).FinalVelocity}\n";
				text += $"HP: {player.health.CurrentHealthValue:0.00} (+{player.health.CurrentInternalInjury:0.00})\n";
				string enumName2 = typeof(PlayerStateType).GetEnumName(player.fsm.State);
				PlayerInputStateType state = player.playerInput.fsm.State;
				text = text + "State: " + enumName2 + " " + (((int)state == 0) ? "" : ((object)(PlayerInputStateType)(ref state)).ToString()) + "\n";
				MappingState val = player.fsm.FindMappingState(player.fsm.State);
				List<(bool, string)> flags = new List<(bool, string)>(9)
				{
					(player.isOnWall, "Wall"),
					(player.isOnLedge, "Ledge"),
					(player.isOnRope, "Rope"),
					(player.kicked, "Kicked"),
					(((Actor)player).onGround, "OnGround"),
					(player.lockMoving, "Locked"),
					(Object.op_Implicit((Object)(object)player.interactableFinder.CurrentInteractableArea), "CanInteract"),
					(player.rollCooldownTimer <= 0f, "CanDash"),
					(player.airJumpCount > 0, "AirJumping")
				};
				(float, string)[] timers = new(float, string)[8]
				{
					(player.rollCooldownTimer, "RollCD"),
					(player.dashCooldownTimer, "DashCD"),
					(player.meleeAttackCooldownTimer, "AttackCD"),
					(player.parryCoolDownTimer, "ParryCD"),
					(player.gadgetCooldownTimer, "GadgetCD"),
					(player.grabHookCooldownTimer, "GrabHookCD"),
					(player.spinMoveCooldownTimer, "SpinMoveCD"),
					(player.jumpGraceTimer, "Coyote")
				};
				text += Flags(flags, timers);
				PlayerAttackState val2 = (PlayerAttackState)(object)((val is PlayerAttackState) ? val : null);
				if (val2 != null)
				{
					string arg = (ReflectionExtension.GetFieldValue<bool>((object)val2, "CanDoMove") ? "" : "!");
					string arg2 = (ReflectionExtension.GetFieldValue<bool>((object)val2, "isAir") ? "" : "!");
					text += string.Format("Attack: {0}CanDoMove {1}IsAir {2}\n", arg, arg2, ReflectionExtension.GetFieldValue<int>((object)val2, "count"));
				}
				else
				{
					text += "\n";
				}
				if ((int)player.jumpState != 0)
				{
					float currentVarJumpTimer = player.currentVarJumpTimer;
					float fieldValue = ReflectionExtension.GetFieldValue<float>((object)player, "GroundJumpRefrenceY");
					float num = ((Component)player).transform.position.y - fieldValue;
					text += string.Format("JumpState {0} {1}h={2:0.00}\n", player.jumpState, (currentVarJumpTimer > 0f) ? (currentVarJumpTimer.ToString("0.00") + " ") : "", num);
				}
				else
				{
					text += "\n";
				}
				text += AnimationText(((Actor)player).animator, filter.HasFlag(DebugFilter.RapidlyChanging));
			}
			HackDrone hackDrone = ((PlayerHackDroneControlState)player.fsm.FindMappingState((PlayerStateType)61)).hackDrone;
			if (hackDrone.fsm != null && (int)hackDrone.fsm.State != 0)
			{
				text += $"\nNymph {hackDrone.fsm.State}\n";
				text += $"  Position: {Vector2.op_Implicit(((Component)hackDrone).transform.position)}\n";
				text += $"  Speed: {Vector2.op_Implicit(hackDrone.droneVel)}\n";
				text = text + "  " + Flags(new <>z__ReadOnlyArray<(bool, string)>(new(bool, string)[2]
				{
					(ReflectionExtension.GetFieldValue<bool>((object)hackDrone, "isDashCD"), "DashCD"),
					(ReflectionExtension.GetFieldValue<bool>((object)hackDrone, "isOutOfRange"), "OutOfRange")
				}), new <>z__ReadOnlySingleElementList<(float, string)>((ReflectionExtension.GetFieldValue<float>((object)hackDrone, "OutOfRangeTimer"), "OutOfRange")), " ");
				text = text + AnimationText(((Actor)hackDrone).animator, filter.HasFlag(DebugFilter.RapidlyChanging)) + "\n";
			}
			GameLevel gameLevel = instance.gameLevel;
			if (Object.op_Implicit((Object)(object)gameLevel))
			{
				text += $"[{gameLevel.SceneName}] ({gameLevel.BlockCountX}x{gameLevel.BlockCountY})";
				if (filter.HasFlag(DebugFilter.RapidlyChanging))
				{
					text += $" dt={Time.deltaTime:0.00000000}\n";
				}
				text += "\n";
			}
			if (Object.op_Implicit((Object)(object)instance.currentCutScene))
			{
				text += $"{instance.currentCutScene}";
			}
			return text;
		}

		private static string Flags(IEnumerable<(bool, string)> flags, IEnumerable<(float, string)> timers, string sep = "\n")
		{
			string text = GeneralExtensions.Join<(bool, string)>(flags.Where<(bool, string)>(((bool, string) x) => x.Item1), (Func<(bool, string), string>)(((bool, string) x) => x.Item2), " ");
			string text2 = GeneralExtensions.Join<(float, string)>(timers.Where<(float, string)>(((float, string) x) => x.Item1 > 0f), (Func<(float, string), string>)(((float, string) x) => $"{x.Item2}({x.Item1:0.000})"), " ");
			return text + sep + text2 + "\n";
		}

		private static string AnimationText(Animator animator, bool includeRapidlyChanging)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
			string text = animator.ResolveHash(currentAnimatorStateInfo.m_Name);
			string text2 = "Animation " + text;
			if (includeRapidlyChanging)
			{
				text2 += $" {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime % 1f * 100f:00.0}%";
			}
			return text2 + "\n";
		}

		public static string GetMonsterInfotext()
		{
			string text = "";
			foreach (MonsterBase value in SingletonBehaviour<MonsterManager>.Instance.monsterDict.Values)
			{
				if (((Behaviour)value).isActiveAndEnabled)
				{
					text = text + GetMonsterInfotext(value) + "\n";
				}
			}
			return text;
		}

		public static string GetMonsterInfotext(MonsterBase monster)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			text = text + MonsterName(monster) + "\n";
			text += $"Pos: {Vector2.op_Implicit(((Component)monster).transform.position)}\n";
			text += $"Speed: {((PhysicsMover)monster).Velocity} + {Vector2.op_Implicit(((Actor)monster).AnimationVelocity)}\n";
			text += $"HP: {monster.health.currentValue:0.00}\n";
			if (monster.monsterCore.attackSequenceMoodule.getCurrentSequence() != null)
			{
				text += "TODO: attack sequence\n";
			}
			if (monster.fsm == null)
			{
				return text + "FSM is null?\n";
			}
			MappingState val = monster.fsm.FindMappingState(monster.fsm.State);
			AnimatorStateInfo currentAnimatorStateInfo = ((Actor)monster).animator.GetCurrentAnimatorStateInfo(0);
			text = text + "State: " + FsmStateName(val);
			text += $" {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime % 1f * 100f:00}%";
			text += "\n";
			BossGeneralState val2 = (BossGeneralState)(object)((val is BossGeneralState) ? val : null);
			if (val2 != null)
			{
				if (Object.op_Implicit((Object)(object)val2.attackQueue))
				{
					text += "AttackQueue:\n";
					foreach (States queuedAttack in val2.attackQueue.QueuedAttacks)
					{
						text = text + "- " + FsmStateName(monster.fsm, queuedAttack) + "\n";
					}
				}
				text += "Queue:\n";
				foreach (States queuedAttack2 in val2.QueuedAttacks)
				{
					text = text + "- " + FsmStateName(monster.fsm, queuedAttack2) + "\n";
				}
				if ((Object)(object)((MonsterState)val2).clip != (Object)null)
				{
					text += "Clip:\n";
					text += $"- {((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime:0.00}\n";
					AnimationEvent[] events = ((MonsterState)val2).clip.events;
					foreach (AnimationEvent val3 in events)
					{
						AnimationEvent val4 = (AnimationEvent)val3.intParameter;
						text += $"- {val3.time:0.00}: {val4}\n";
					}
				}
			}
			MonsterHurtInterrupt hurtInterrupt = monster.HurtInterrupt;
			if (((Behaviour)hurtInterrupt).isActiveAndEnabled)
			{
				float fieldValue = ReflectionExtension.GetFieldValue<float>((object)hurtInterrupt, "AccumulateDamageTh");
				if (fieldValue > 0f)
				{
					text += $"Hurt Interrupt: {hurtInterrupt.currentAccumulateDamage / (float)monster.postureSystem.FullPostureValue:0.00} > {fieldValue}\n";
				}
			}
			_ = (bool)typeof(MonsterBase).GetMethod("MonsterStatCanCriticalHit", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(monster, Array.Empty<object>());
			text += "Attack sensors:\n";
			foreach (AttackSensor item in VersionCompatExtensions.AttackSensorsCompat(monster))
			{
				ReNumPrefix.Replace(((Object)item).name, "");
				AbstractConditionComp[] array = ReflectionExtension.GetFieldValue<AbstractConditionComp[]>((object)item, "_conditions") ?? Array.Empty<AbstractConditionComp>();
				for (int i = 0; i < array.Length; i++)
				{
					string text2 = FormatCondition(array[i]);
					text = text + "   if: " + text2 + "\n";
				}
			}
			_ = monster.fsm.FindMappingState((States)3) is StealthEngaging;
			return text;
		}

		private static string FsmStateName(MappingState mappingState)
		{
			return ReCjk.Replace(((Object)mappingState).name, "").Trim();
		}

		private static string FsmStateName(StateMachine<States> monster, States state)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			MappingState val = monster.FindMappingState(state);
			if (val != null)
			{
				return FsmStateName(val);
			}
			return ((object)(States)(ref state)).ToString();
		}

		private static string MonsterName(MonsterBase monster)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)(LocalizedString)(ref ((MonsterStat)(typeof(MonsterBase).GetField("_monsterStat") ?? typeof(MonsterBase).GetField("monsterStat")).GetValue(monster)).monsterName)).ToString();
			if (text != "")
			{
				return text;
			}
			return StringExtensions.TrimEndMatches(StringExtensions.TrimStartMatches(StringExtensions.TrimStartMatches(((Object)monster).name, (ReadOnlySpan<char>)"StealthGameMonster_"), (ReadOnlySpan<char>)"TrapMonster_"), (ReadOnlySpan<char>)"(Clone)").ToString();
		}

		private static string FormatCondition(AbstractConditionComp condition)
		{
			string arg = StringExtensions.TrimStartMatches(((Object)condition).name, (ReadOnlySpan<char>)"[Condition] ").ToString();
			string text = "";
			FlagBoolCondition val = (FlagBoolCondition)(object)((condition is FlagBoolCondition) ? condition : null);
			if (val == null)
			{
				GeneralCondition val2 = (GeneralCondition)(object)((condition is GeneralCondition) ? condition : null);
				if (val2 == null)
				{
					PlayerMovePredictCondition val3 = (PlayerMovePredictCondition)(object)((condition is PlayerMovePredictCondition) ? condition : null);
					if (val3 != null)
					{
						text += "Player";
						if (val3.ParryDetect)
						{
							text += " Parry";
						}
						if (val3.DodgeDetect)
						{
							text += " Dash";
						}
						if (val3.JumpDetect)
						{
							text += " Jump";
						}
						if (val3.InAirDetect)
						{
							text += " InAir";
						}
						if (val3.AttackDetect)
						{
							text += " Attack";
						}
						if (val3.ThirdAttackDetect)
						{
							text += " Third";
						}
						if (val3.ChargeAttackDetect)
						{
							text += " Charged";
						}
						if (val3.FooDetect)
						{
							text += " Foo";
						}
						if (val3.ArrowDetect)
						{
							text += " Shoots";
						}
						if ((double)val3.randomChance != 1.0)
						{
							text += $" at {val3.randomChance * 100f:0}%";
						}
					}
					else
					{
						text += $" {((object)condition).GetType()}";
					}
				}
				else
				{
					text += $" {val2}";
				}
			}
			else
			{
				string arg2 = FormatVariable((AbstractVariable?)(object)val.flagBool);
				VariableBool flagBool = val.flagBool;
				text = $"{arg} bool flag {arg2} current {((flagBool != null) ? new bool?(flagBool.FlagValue) : null)}";
				string text2 = text;
				VariableBool flagBool2 = val.flagBool;
				object obj;
				if (flagBool2 == null)
				{
					obj = null;
				}
				else
				{
					ScriptableDataBool boolFlag = flagBool2.boolFlag;
					obj = ((boolFlag != null) ? ((GameFlagBase)boolFlag).FinalSaveID : null);
				}
				text = text2 + " " + (string?)obj;
				text += $" {val.flagBool}";
			}
			if (condition.FinalResultInverted)
			{
				text = "(inverted) " + text;
			}
			return "(" + (condition.FinalResult ? "true" : "false") + ") " + text;
		}

		private static string FormatVariable(AbstractVariable? variable)
		{
			if ((Object)(object)variable == (Object)null)
			{
				return "null";
			}
			string text = StringExtensions.TrimEndMatches(StringExtensions.TrimStartMatches(((object)variable).ToString(), (ReadOnlySpan<char>)"[Variable] "), (ReadOnlySpan<char>)" (VariableBool)").ToString();
			GameFlagBase finalData = variable.FinalData;
			return text + " " + ((finalData != null) ? finalData.GetSaveID : null);
		}
	}
}
namespace System.Diagnostics.CodeAnalysis
{
	[AttributeUsage(AttributeTargets.Constructor)]
	public sealed class SetsRequiredMembersAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	internal static class IsExternalInit
	{
	}
	public class RequiredMemberAttribute : Attribute
	{
	}
	public class CompilerFeatureRequiredAttribute : Attribute
	{
		public CompilerFeatureRequiredAttribute(string name)
		{
		}
	}
}
namespace DebugModPlus
{
	[AttributeUsage(AttributeTargets.Method, Inherited = false)]
	[MeansImplicitUse]
	public class BindableMethod : Attribute
	{
		public string? Name;

		public KeyCode[]? DefaultKeybind;
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("DebugModPlus", "DebugModPlus", "1.10.0")]
	public class DebugModPlus : BaseUnityPlugin
	{
		public static DebugModPlus Instance;

		private DebugUI debugUI;

		private QuantumConsoleModule quantumConsoleModule = new QuantumConsoleModule();

		private Harmony harmony;

		private InfotextModule InfotextModule;

		public HitboxModule HitboxModule;

		public SavestateModule SavestateModule;

		public SpeedrunTimerModule SpeedrunTimerModule;

		private FsmInspectorModule fsmInspectorModule = new FsmInspectorModule();

		public GhostModule GhostModule;

		private ConfigEntry<KeyboardShortcut> configShortcutFsmPickerModifier;

		private Dictionary<KeyboardShortcut, string> configSavestateShortcutsCreate;

		private Dictionary<KeyboardShortcut, string> configSavestateShortcutsLoad;

		internal ConfigEntry<HitboxType> HitboxFilter;

		private bool initializedSuccessfully;

		internal static bool JustGainedFocus;

		private void HandleLog(string logString, string stackTrace, LogType type)
		{
			ToastManager.Toast((object)logString);
		}

		private void Awake()
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: 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)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Expected O, but got Unknown
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0331: Unknown result type (might be due to invalid IL or missing references)
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log.Init(((BaseUnityPlugin)this).Logger);
			Log.Info("Plugin DebugModPlus started loading...");
			try
			{
				harmony = Harmony.CreateAndPatchAll(typeof(DebugModPlus).Assembly, (string)null);
				Type type = GameVersions.Select<Type>("d4c12f4d7e8442e79988244014fb92d2", typeof(PatchesSpeedrunPatch), typeof(PatchesCurrentPatch));
				harmony.PatchAll(type);
				Log.Info($"Patched {harmony.GetPatchedMethods().Count()} methods...");
				ConfigEntry<TimerMode> configTimerMode = ((BaseUnityPlugin)this).Config.Bind<TimerMode>("SpeedrunTimer", "Timer Mode", TimerMode.Triggers, (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> changeModeShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Cycle Timer Mode", default(KeyboardShortcut), (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> resetTimerShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Reset Timer", default(KeyboardShortcut), (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> pauseTimerShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Pause Timer", default(KeyboardShortcut), (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> setStartpointShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Set Startpoint", default(KeyboardShortcut), (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> setEndpointShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Set Endpoint", default(KeyboardShortcut), (ConfigDescription)null);
				ConfigEntry<KeyboardShortcut> clearCheckpointsShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("SpeedrunTimer Shortcuts", "Clear Checkpoints", default(KeyboardShortcut), (ConfigDescription)null);
				configShortcutFsmPickerModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Shortcuts", "FSM Picker Modifier", default(KeyboardShortcut), new ConfigDescription("When this key is pressed and you click on a sprite, it will try to open the FSM inspector for that object", (AcceptableValueBase)null, Array.Empty<object>()));
				ConfigEntry<bool> configRecordGhost = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedrunTimer", "Record Ghost", false, (ConfigDescription)null);
				ConfigEntry<Color> ghostColor = ((BaseUnityPlugin)this).Config.Bind<Color>("SpeedrunTimer", "PB Ghost Color", new Color(1f, 0.8f, 0f, 0.5f), (ConfigDescription)null);
				ConfigEntry<bool> configPauseStopsTimer = ((BaseUnityPlugin)this).Config.Bind<bool>("SpeedrunTimer", "Pause Timer Stops Speedrun Timer", false, (ConfigDescription)null);
				ConfigEntry<SavestateFilter> currentFilter = ((BaseUnityPlugin)this).Config.Bind<SavestateFilter>("Savestates", "Savestate filter", SavestateFilter.Flags | SavestateFilter.Player, (ConfigDescription)null);
				ConfigEntry<SavestateLoadMode> loadMode = ((BaseUnityPlugin)this).Config.Bind<SavestateLoadMode>("Savestates", "Savestate load mode", SavestateLoadMode.None, (ConfigDescription)null);
				ConfigEntry<InfotextModule.InfotextFilter> filter = ((BaseUnityPlugin)this).Config.Bind<InfotextModule.InfotextFilter>("Info Text Panel", "Show Info", global::DebugModPlus.Modules.InfotextModule.InfotextFilter.GameInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.BasicPlayerInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.AdvancedPlayerInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.RespawnInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.DamageInfo | global::DebugModPlus.Modules.InfotextModule.InfotextFilter.InteractableInfo, (ConfigDescription)null);
				HitboxFilter = ((BaseUnityPlugin)this).Config.Bind<HitboxType>("The rest", "Hitbox Filter", HitboxType.Default, (ConfigDescription)null);
				HitboxFilter.SettingChanged += delegate
				{
					HitboxModule.HitboxesVisible = true;
				};
				configSavestateShortcutsCreate = new Dictionary<KeyboardShortcut, string>();
				configSavestateShortcutsLoad = new Dictionary<KeyboardShortcut, string>();
				InfotextModule = new InfotextModule(filter);
				SavestateModule = new SavestateModule(currentFilter, loadMode, ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Save", new KeyboardShortcut((KeyCode)270, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Load", new KeyboardShortcut((KeyCode)271, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Delete", new KeyboardShortcut((KeyCode)269, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Page next", new KeyboardShortcut((KeyCode)275, Array.Empty<KeyCode>()), (ConfigDescription)null), ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Savestates", "Page prev", new KeyboardShortcut((KeyCode)276, Array.Empty<KeyCode>()), (ConfigDescription)null));
				SpeedrunTimerModule = new SpeedrunTimerModule(configTimerMode, configRecordGhost, configPauseStopsTimer);
				GhostModule = new GhostModule(ghostColor);
				SavestateModule.SavestateLoaded += delegate
				{
					SpeedrunTimerModule.OnSavestateLoaded();
				};
				SavestateModule.SavestateCreated += delegate
				{
					SpeedrunTimerModule.OnSavestateCreated();
				};
				HitboxModule = new GameObject().AddComponent<HitboxModule>();
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)quantumConsoleModule.ToggleConsole, (KeyCode[])(object)new KeyCode[2]
				{
					(KeyCode)306,
					(KeyCode)46
				});
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)ToggleSettings, (KeyCode[])(object)new KeyCode[2]
				{
					(KeyCode)306,
					(KeyCode)44
				});
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.CycleTimerMode();
				}, (Func<KeyboardShortcut>)(() => changeModeShortcut.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.ResetTimerUser();
				}, (Func<KeyboardShortcut>)(() => resetTimerShortcut.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.PauseTimer();
				}, (Func<KeyboardShortcut>)(() => pauseTimerShortcut.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.SetStartpoint();
				}, (Func<KeyboardShortcut>)(() => setStartpointShortcut.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.SetEndpoint();
				}, (Func<KeyboardShortcut>)(() => setEndpointShortcut.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					SpeedrunTimerModule.ClearCheckpoints();
				}, (Func<KeyboardShortcut>)(() => clearCheckpointsShortcut.Value));
				debugUI = ((Component)this).gameObject.AddComponent<DebugUI>();
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(FreecamModule));
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(TimeModule));
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(InfotextModule));
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(HitboxModule));
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(SavestateModule));
				debugUI.AddBindableMethods(((BaseUnityPlugin)this).Config, typeof(CheatModule));
				FlagLoggerModule.Awake();
				RCGLifeCycle.DontDestroyForever(((Component)this).gameObject);
				RCGLifeCycle.DontDestroyForever(((Component)HitboxModule).gameObject);
				QuantumConsoleModule.Initialize();
				Log.Info("Plugin DebugModPlus is loaded!");
				initializedSuccessfully = true;
			}
			catch (Exception data)
			{
				Log.Error(data);
			}
		}

		private void ToggleSettings()
		{
			debugUI.settingsOpen = !debugUI.settingsOpen;
			_ = Player.i;
		}

		private void OnApplicationFocus(bool hasFocus)
		{
			JustGainedFocus |= hasFocus;
		}

		private void Update()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Invalid comparison between Unknown and I4
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			if (!initializedSuccessfully)
			{
				return;
			}
			FreecamModule.Update();
			MapTeleportModule.Update();
			InfotextModule.Update();
			SavestateModule.Update();
			bool flag = false;
			foreach (KeyValuePair<KeyboardShortcut, string> item in configSavestateShortcutsCreate)
			{
				if (KeybindManager.CheckShortcutOnly(item.Key))
				{
					SavestateModule.CreateSavestate(item.Value);
					flag = true;
				}
			}
			if (!flag)
			{
				foreach (KeyValuePair<KeyboardShortcut, string> item2 in configSavestateShortcutsLoad)
				{
					if (KeybindManager.CheckShortcutOnly(item2.Key))
					{
						SavestateModule.LoadSavestateAt(item2.Value);
					}
				}
			}
			Player i = Player.i;
			PlayerInputStateType? val = ((i != null) ? new PlayerInputStateType?(i.playerInput.fsm.State) : null);
			bool flag2 = !val.HasValue || (int)val.GetValueOrDefault() != 1;
			KeyboardShortcut value = configShortcutFsmPickerModifier.Value;
			if (((KeyboardShortcut)(ref value)).IsPressed() && Input.GetMouseButtonDown(0))
			{
				fsmInspectorModule.Objects.Clear();
				if (flag2)
				{
					Cursor.visible = true;
					TryPickFsm();
				}
			}
			JustGainedFocus = false;
		}

		private void TryPickFsm()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			fsmInspectorModule.Objects.Clear();
			try
			{
				Camera theRealSceneCamera = SingletonBehaviour<CameraManager>.Instance.cameraCore.theRealSceneCamera;
				Vector3 worldPosition = theRealSceneCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0f - ((Component)theRealSceneCamera).transform.position.z));
				worldPosition.z = 0f;
				GameObject val = (from x in ((IEnumerable<GameObject>)PickVisible(worldPosition)).Select((Func<GameObject, GameObject>)delegate(GameObject sprite)
					{
						StateMachineOwner componentInParent = sprite.GetComponentInParent<StateMachineOwner>();
						object obj = ((componentInParent != null) ? ((Component)componentInParent).gameObject : null);
						if (obj == null)
						{
							FSMStateMachineRunner componentInParent2 = sprite.GetComponentInParent<FSMStateMachineRunner>();
							if (componentInParent2 == null)
							{
								return null;
							}
							obj = ((Component)componentInParent2).gameObject;
						}
						return (GameObject)obj;
					})
					where Object.op_Implicit((Object)(object)x)
					select x).Distinct().FirstOrDefault();
				if (Object.op_Implicit((Object)(object)val))
				{
					fsmInspectorModule.Objects.Add(val);
				}
				else
				{
					ToastManager.Toast((object)"No state machine found at cursor");
				}
			}
			catch (Exception ex)
			{
				ToastManager.Toast((object)ex);
			}
		}

		private List<GameObject> PickVisible(Vector3 worldPosition)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return (from x in (from t in (from renderer in Object.FindObjectsOfType<SpriteRenderer>()
						select (((Component)renderer).gameObject, ((Renderer)renderer).bounds)).Concat(from renderer in Object.FindObjectsOfType<ParticleSystemRenderer>()
						select (((Component)renderer).gameObject, ((Renderer)renderer).bounds))
					where ((Bounds)(ref t.bounds)).Contains(worldPosition)
					select t).Where<(GameObject, Bounds)>(delegate((GameObject gameObject, Bounds bounds) t)
				{
					string text = ((Object)t.gameObject.gameObject).name.ToLower();
					Transform parent = t.gameObject.gameObject.transform.parent;
					string text2 = ((parent != null) ? ((Object)parent).name : null) ?? "";
					return !text.Contains("light") && !text.Contains("fade") && !text.Contains("glow") && !text.Contains("attack") && !text2.Contains("Vibe") && !text2.Contains("Skin");
				})
				select x.gameObject).ToList();
		}

		private void LateUpdate()
		{
			if (!initializedSuccessfully)
			{
				return;
			}
			try
			{
				GhostModule.LateUpdate();
				SpeedrunTimerModule.LateUpdate();
			}
			catch (Exception data)
			{
				Log.Error(data);
			}
		}

		private void OnGUI()
		{
			if (!initializedSuccessfully)
			{
				return;
			}
			try
			{
				SpeedrunTimerModule.OnGui();
			}
			catch (Exception arg)
			{
				Log.Error($"Error in SpeedrunTimerModule: {arg}");
			}
			try
			{
				fsmInspectorModule.OnGui();
			}
			catch (Exception arg2)
			{
				Log.Error($"Error in fsm inspector module: {arg2}");
			}
			try
			{
				SavestateModule.OnGui();
			}
			catch (Exception arg3)
			{
				Log.Error($"Error in SavestateModule: {arg3}");
			}
			try
			{
				InfotextModule.OnGui();
			}
			catch (Exception arg4)
			{
				Log.Error($"Error in InfotextModule: {arg4}");
			}
		}

		private void OnDestroy()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			Application.logMessageReceived -= new LogCallback(HandleLog);
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			GhostModule?.Unload();
			SpeedrunTimerModule?.Destroy();
			InfotextModule?.Destroy();
			HitboxModule hitboxModule = HitboxModule;
			if (Object.op_Implicit((Object)(object)((hitboxModule != null) ? ((Component)hitboxModule).gameObject : null)))
			{
				Object.Destroy((Object)(object)((Component)HitboxModule).gameObject);
			}
			Log.Info("Plugin DebugModPlus unloaded\n\n");
		}
	}
	[PublicAPI]
	public class DebugSave
	{
		public const int DebugSaveIndex = 100;

		public static void LoadDebugSave()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SingletonBehaviour<SaveManager>.Instance.LoadSaveAtSlot(100);
			SingletonBehaviour<ApplicationUIGroupManager>.Instance.ClearAll();
			RuntimeInitHandler.LoadCore();
			if (!GameVersions.IsVersion("d4c12f4d7e8442e79988244014fb92d2"))
			{
				typeof(GameConfig).GetMethod("InstantiateGameCore").Invoke(ScriptableObjectSingleton<GameConfig>.Instance, Array.Empty<object>());
			}
		}
	}
	internal class DebugActionToggle
	{
		public bool Value;

		public required Action<bool> OnChange;
	}
	internal class DebugAction
	{
		public required Action OnChange;
	}
	public class DebugUI : MonoBehaviour
	{
		public bool settingsOpen;

		private GUIStyle? styleButton;

		private GUIStyle? styleToggle;

		private Dictionary<string, DebugActionToggle> toggles = new Dictionary<string, DebugActionToggle>();

		private Dictionary<string, DebugAction> actions = new Dictionary<string, DebugAction>();

		private void Awake()
		{
			toggles.Clear();
		}

		public void AddBindableMethods(ConfigFile config, Type ty)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo[] methods = ty.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				BindableMethod customAttribute = methodInfo.GetCustomAttribute<BindableMethod>();
				if (customAttribute != null)
				{
					string text = customAttribute.Name ?? methodInfo.Name;
					Action action = (Action)Delegate.CreateDelegate(typeof(Action), methodInfo);
					string text2 = new string(Array.FindAll(text.ToCharArray(), char.IsLetterOrDigit));
					ConfigEntry<KeyboardShortcut> keyboardShortcut = config.Bind<KeyboardShortcut>("Shortcuts", text2, (customAttribute.DefaultKeybind != null) ? new KeyboardShortcut(customAttribute.DefaultKeybind[^1], customAttribute.DefaultKeybind[..^1]) : default(KeyboardShortcut), (ConfigDescription)null);
					actions.Add(text, new DebugAction
					{
						OnChange = action
					});
					KeybindManager.Add((MonoBehaviour)(object)this, action, (Func<KeyboardShortcut>)(() => keyboardShortcut.Value));
				}
			}
		}

		public void AddToggle(string actionName, Action<bool> onChange, bool defaultValue = false)
		{
			toggles.Add(actionName, new DebugActionToggle
			{
				Value = defaultValue,
				OnChange = onChange
			});
		}

		private void OnGUI()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			if (!settingsOpen)
			{
				return;
			}
			RCGInput.SetCursorVisible(true);
			if (styleButton == null)
			{
				styleButton = new GUIStyle(GUI.skin.box)
				{
					alignment = (TextAnchor)5,
					padding = new RectOffset(20, 20, 20, 20),
					fontSize = 20
				};
			}
			if (styleToggle == null)
			{
				styleToggle = new GUIStyle(GUI.skin.toggle)
				{
					fontSize = 20
				};
			}
			GUILayout.BeginArea(new Rect(20f, 20f, (float)(Screen.width - 40), (float)(Screen.height - 40)));
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			string key;
			foreach (KeyValuePair<string, DebugActionToggle> toggle in toggles)
			{
				toggle.Deconstruct(out key, out var value);
				string arg = key;
				DebugActionToggle debugActionToggle = value;
				if (GUILayout.Button($"{arg}: {debugActionToggle.Value}", styleButton, Array.Empty<GUILayoutOption>()))
				{
					debugActionToggle.Value = !debugActionToggle.Value;
					debugActionToggle.OnChange(debugActionToggle.Value);
					ToastManager.Toast((object)$"change {arg} to {debugActionToggle.Value}");
				}
			}
			foreach (KeyValuePair<string, DebugAction> action in actions)
			{
				action.Deconstruct(out key, out var value2);
				object obj = key;
				DebugAction debugAction = value2;
				if (obj == null)
				{
					obj = "";
				}
				if (GUILayout.Button((string)obj, styleButton, Array.Empty<GUILayoutOption>()))
				{
					debugAction.OnChange();
				}
			}
			GUILayout.EndVertical();
			GUILayout.EndHorizontal();
			GUILayout.FlexibleSpace();
			GUILayout.EndArea();
		}
	}
	[HarmonyPatch]
	public class FastLoads
	{
		public static bool Enabled
		{
			get
			{
				if (!FreecamModule.FreecamActive)
				{
					return SavestateModule.IsLoadingSavestate;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(GameCore), "FadeOutBlack")]
		[HarmonyPrefix]
		private static void FadeOutBlack(ref float fadeTime, ref float delayTime)
		{
			if (Enabled)
			{
				fadeTime = 0f;
				delayTime = 0f;
			}
		}

		[HarmonyPatch(typeof(UIExtension), "AddUITask")]
		[HarmonyPrefix]
		private static void AddUiTask(MonoBehaviour mb, Action action, ref float delay)
		{
			if (Enabled)
			{
				delay = 0f;
			}
		}
	}
	public class GameInfo
	{
		private static float statsLastHP = 0f;

		private static float statsLastIntDmg = 0f;

		private static Vector2 statsLastPos = Vector2.zero;

		private static MovingAverage averagePlayerX = new MovingAverage();

		private static MovingAverage averagePlayerY = new MovingAverage();

		private float playerLastHP = statsLastHP;

		private float playerLastIntDmg = statsLastIntDmg;

		public string? ErrorText;

		public string GameLevel = "";

		public string CoreState = "";

		public string Cutscene = "";

		public float PlayerHp;

		public float PlayerLostHp;

		public float PlayerMaxHp;

		public float PlayerIntNewDmg;

		public float PlayerIntDmg;

		public Vector2 PlayerPos;

		public Vector2 PlayerSafePos;

		public Vector2 SceneRespawn;

		public Vector2 PlayerRespawn;

		public Vector2 PlayerSpeed;

		public Vector2 PlayerAvgSpeed;

		public string playerState = "";

		public string PlayerJumpState = "";

		public string PlayerJumpTimer = "";

		public bool PlayerRope;

		public float PlayerRopeX;

		public bool PlayerWall;

		public bool PlayerLedge;

		public bool PlayerKicked;

		public bool DebugAutoHeal;

		public bool DebugInvincibility;

		public float EnemyHP;

		public float CummHPDmg;

		public float CummIntDmg;

		public int FruitCount;

		public int Fruit;

		public int GreaterFruit;

		public int TwinFruit;

		public float AttackDamage;

		public float FooDamage;

		public List<string> Interactables = new List<string>();

		public GameInfo()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Expected O, but got Unknown
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: 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_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Invalid comparison between Unknown and I4
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: 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)
			//IL_01fb: Invalid comparison between Unknown and I4
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Invalid comparison between Unknown and I4
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!SingletonBehaviour<GameCore>.IsAvailable())
				{
					return;
				}
				GameCore instance = SingletonBehaviour<GameCore>.Instance;
				Player player = instance.player;
				if (player == null)
				{
					Log.Error("Error during InfoText collection: player or core is null");
					return;
				}
				Scene activeScene = SceneManager.GetActiveScene();
				GameLevel = ((Scene)(ref activeScene)).name;
				GameCoreState currentCoreState = instance.currentCoreState;
				CoreState = ((object)(GameCoreState)(ref currentCoreState)).ToString();
				if (Object.op_Implicit((Object)(object)instance.currentCutScene))
				{
					Cutscene = ((Object)instance.currentCutScene).name;
				}
				PlayerHealth val = (PlayerHealth)player.GetHealth;
				if (val != null)
				{
					PlayerMaxHp = ((Health)val).maxHealth.Value;
					PlayerHp = val.CurrentHealthValue;
					if (PlayerHp != statsLastHP)
					{
						PlayerLostHp = PlayerHp - statsLastHP;
						statsLastHP = PlayerHp;
					}
					PlayerIntDmg = val.CurrentInternalInjury;
					if (PlayerIntDmg != playerLastIntDmg)
					{
						PlayerIntNewDmg = PlayerIntDmg - playerLastIntDmg;
					}
				}
				if (Object.op_Implicit((Object)(object)instance.gameLevel))
				{
					(SpawnType, Vector3) nearestSpawnPoint = SingletonBehaviour<GameCore>.Instance.gameLevel.GetNearestSpawnPoint();
					SpawnType item2 = nearestSpawnPoint.Item1;
					PlayerPos = Vector2.op_Implicit(((Component)player).transform.position);
					PlayerSafePos = Vector2.op_Implicit(player.lastSafeGroundPosition);
					PlayerRespawn = (SceneRespawn = Vector2.op_Implicit(nearestSpawnPoint.Item2));
					if ((int)item2 == 3)
					{
						PlayerRespawn = PlayerSafePos;
					}
					else if (player.SafeGroundRecorder.LastSafeGroundPositionList.Count > 0 && ((int)item2 == 1 || (int)item2 == 2))
					{
						PlayerRespawn = PlayerSafePos;
					}
					else
					{
						Vector3 position = ((Component)SingletonBehaviour<CameraManager>.Instance.cameraCore.theRealSceneCamera).transform.position;
						float num = Vector2.Distance(Vector2.op_Implicit(position), SceneRespawn);
						if (Vector2.Distance(Vector2.op_Implicit(position), PlayerSafePos) < num)
						{
							PlayerRespawn = PlayerSafePos;
						}
					}
				}
				PlayerSpeed = ((Actor)player).FinalVelocity;
				averagePlayerX.Sample((long)PlayerSpeed.x);
				averagePlayerY.Sample((long)PlayerSpeed.y);
				PlayerAvgSpeed = new Vector2(averagePlayerX.GetAverageFloat, averagePlayerY.GetAverageFloat);
				playerState = ((Object)player.CurrentState).name;
				PlayerRope = Object.op_Implicit((Object)(object)player.touchingRope);
				if (PlayerRope)
				{
					PlayerRopeX = ((Component)player.touchingRope).transform.position.x;
				}
				PlayerWall = player.isOnWall;
				PlayerLedge = player.isOnLedge;
				PlayerKicked = player.kicked;
				PlayerJumpState jumpState = player.jumpState;
				PlayerJumpState = ((object)(PlayerJumpState)(ref jumpState)).ToString();
				if ((int)player.jumpState != 0)
				{
					float currentVarJumpTimer = player.currentVarJumpTimer;
					PlayerJumpTimer = ((currentVarJumpTimer > 0f) ? currentVarJumpTimer.ToString("0.00") : "");
				}
				Fruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item)
				{
					ItemData val4 = (ItemData)(object)((item is ItemData) ? item : null);
					return val4 != null && ((GameFlagDescriptable)val4).Title == "Tao Fruit";
				})).ownNum).CurrentValue;
				GreaterFruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item)
				{
					ItemData val3 = (ItemData)(object)((item is ItemData) ? item : null);
					return val3 != null && ((GameFlagDescriptable)val3).Title == "Greater Tao Fruit";
				})).ownNum).CurrentValue;
				TwinFruit = ((FlagField<int>)(object)((ItemData)ScriptableObjectSingleton<GameConfig>.Instance.allGameFlags.Flags.Find(delegate(GameFlagBase item)
				{
					ItemData val2 = (ItemData)(object)((item is ItemData) ? item : null);
					return val2 != null && ((GameFlagDescriptable)val2).Title == "Twin Tao Fruit";
				})).ownNum).CurrentValue;
				FruitCount = Fruit + GreaterFruit + TwinFruit;
				AttackDamage = player.normalAttackDealer.FinalValue;
				FooDamage = player.fooEffectDealer.FinalValue;
				InteractableArea currentInteractableArea = player.interactableFinder.CurrentInteractableArea;
				if (currentInteractableArea == null)
				{
					return;
				}
				foreach (AbstractInteraction validInteraction in currentInteractableArea.ValidInteractions)
				{
					Interactables.Add(((Object)((Component)((Component)validInteraction).transform.parent).transform.parent).name);
				}
			}
			catch (Exception ex)
			{
				ErrorText = ex.ToString();
				Log.Error(ErrorText);
			}
		}
	}
	internal static class Log
	{
		private static ManualLogSource logSource;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void Debug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			logSource.LogWarning(data);
		}
	}
	public static class PatchesSpeedrunPatch
	{
		[HarmonyPatch(typeof(GameCore), "FadeToBlack")]
		[HarmonyPrefix]
		private static void FadeToBlack(ref float fadeTime)
		{
			if (FastLoads.Enabled)
			{
				fadeTime = 0f;
			}
		}

		[HarmonyPatch(typeof(GameCore), "ChangeScene", new Type[]
		{
			typeof(ChangeSceneData),
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static void ChangeScene(ref ChangeSceneData changeSceneData, ref bool showTip, bool captureLastImage)
		{
			DebugModPlus.Instance.SpeedrunTimerModule.OnLevelChange();
			if (FastLoads.Enabled)
			{
				showTip = false;
			}
		}
	}
	public static class PatchesCurrentPatch
	{
		[HarmonyPatch(typeof(GameCore), "FadeToBlack", new Type[]
		{
			typeof(float),
			typeof(float)
		})]
		[HarmonyPatch(typeof(GameCore), "FadeToBlack", new Type[]
		{
			typeof(float),
			typeof(UnityAction),
			typeof(float)
		})]
		[HarmonyPrefix]
		private static void FadeToBlack(ref float fadeTime)
		{
			if (FastLoads.Enabled)
			{
				fadeTime = 0f;
			}
		}

		[HarmonyPatch(typeof(GameCore), "ChangeScene", new Type[]
		{
			typeof(ChangeSceneData),
			typeof(bool),
			typeof(bool),
			typeof(float)
		})]
		[HarmonyPrefix]
		private static void ChangeScene(ref ChangeSceneData changeSceneData, ref bool showTip, bool captureLastImage, ref float delayTime)
		{
			DebugModPlus.Instance.SpeedrunTimerModule.OnLevelChange();
			if (FastLoads.Enabled)
			{
				delayTime = 0f;
				showTip = false;
			}
		}
	}
	public class AnimatorSnapshot
	{
		public required int StateHash;

		public required float NormalizedTime;

		public required Dictionary<int, float> ParamsFloat;

		public required Dictionary<int, int> ParamsInt;

		public required Dictionary<int, bool> ParamsBool;

		public static AnimatorSnapshot Snapshot(Animator animator)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected I4, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Invalid comparison between Unknown and I4
			AnimatorStateInfo currentAnimatorStateInfo = animator.GetCurrentAnimatorStateInfo(0);
			AnimatorControllerParameter[] parameters = animator.parameters;
			Dictionary<int, float> dictionary = new Dictionary<int, float>();
			Dictionary<int, bool> dictionary2 = new Dictionary<int, bool>();
			Dictionary<int, int> dictionary3 = new Dictionary<int, int>();
			AnimatorControllerParameter[] array = parameters;
			foreach (AnimatorControllerParameter val in array)
			{
				AnimatorControllerParameterType type = val.type;
				switch (type - 1)
				{
				default:
					if ((int)type == 9)
					{
						continue;
					}
					break;
				case 0:
					dictionary[val.nameHash] = animator.GetFloat(val.nameHash);
					continue;
				case 3:
					dictionary2[val.nameHash] = animator.GetBool(val.nameHash);
					continue;
				case 2:
					dictionary3[val.nameHash] = animator.GetInteger(val.nameHash);
					continue;
				case 1:
					break;
				}
				ToastManager.Toast((object)$"Unsnapshotted param {val.type}");
			}
			return new AnimatorSnapshot
			{
				StateHash = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash,
				NormalizedTime = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime,
				ParamsFloat = dictionary,
				ParamsInt = dictionary3,
				ParamsBool = dictionary2
			};
		}

		public void Restore(Animator animator)
		{
			if ((Object)(object)animator == (Object)null)
			{
				return;
			}
			if (((Object)animator).name == "Animator")
			{
				Transform val = ((Component)animator).transform;
				while (Object.op_Implicit((Object)(object)val))
				{
					((Component)val).gameObject.SetActive(true);
					val = val.parent;
				}
			}
			animator.Play(StateHash, 0, NormalizedTime);
			animator.Update(0f);
			foreach (KeyValuePair<int, float> item in ParamsFloat)
			{
				animator.SetFloat(item.Key, item.Value);
			}
			foreach (KeyValuePair<int, int> item2 in ParamsInt)
			{
				animator.SetInteger(item2.Key, item2.Value);
			}
			foreach (KeyValuePair<int, bool> item3 in ParamsBool)
			{
				animator.SetBool(item3.Key, item3.Value);
			}
		}
	}
	public class Savestate
	{
		private class ForceSerializeResolver : DefaultContractResolver
		{
			public List<Type> ForceSerializePropertiesOf = new List<Type>();

			protected override List<MemberInfo> GetSerializableMembers(Type objectType)
			{
				if (ForceSerializePropertiesOf.Contains(objectType))
				{
					return objectType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Cast<MemberInfo>().ToList();
				}
				return ((DefaultContractResolver)this).GetSerializableMembers(objectType);
			}

			protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
			{
				return ((DefaultContractResolver)this).CreateProperty(member, (MemberSerialization)2);
			}
		}

		public string? Scene;

		public Vector3? PlayerPosition;

		public string? LastTeleportId;

		public List<ComponentSnapshot>? MonobehaviourSnapshots;

		public List<GameObjectSnapshot>? GameObjectSnapshots;

		public List<MonsterLoveFsmSnapshot>? FsmSnapshots;

		public List<GeneralFsmSnapshot>? GeneralFsmSnapshots;

		public List<ReferenceFixups>? ReferenceFixups;

		public JObject? Flags;

		public State? RandomState;

		private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings
		{
			Formatting = (Formatting)1,
			NullValueHandling = (NullValueHandling)1,
			ContractResolver = (IContractResolver)(object)new ForceSerializeResolver
			{
				ForceSerializePropertiesOf = new List<Type>(1) { typeof(State) }
			},
			Converters = new List<JsonConverter>(1) { (JsonConverter)(object)new Vector3Converter() }
		};

		public void SerializeTo(StreamWriter writer)
		{
			JsonSerializer.Create(jsonSettings).Serialize((TextWriter)writer, (object)this);
		}

		public static Savestate DeserializeFrom(StreamReader reader)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Expected O, but got Unknown
			JsonTextReader val = new JsonTextReader((TextReader)reader);
			return JsonSerializer.Create(jsonSettings).Deserialize<Savestate>((JsonReader)(object)val) ?? throw new Exception("Failed to deserialize savestate");
		}

		public string Serialize()
		{
			return JsonConvert.SerializeObject((object)this, (Formatting)1);
		}

		public static Savestate Deserialize(string data)
		{
			return JsonConvert.DeserializeObject<Savestate>(data) ?? throw new Exception("Failed to deserialize savestate");
		}
	}
	public record GameObjectData(bool Active);
	public class GameObjectSnapshot
	{
		public required string Path;

		public required GameObjectData Data;

		public static GameObjectSnapshot Of(GameObject go)
		{
			return new GameObjectSnapshot
			{
				Path = ObjectUtils.ObjectPath(go),
				Data = new GameObjectData(go.activeSelf)
			};
		}

		public bool Restore()
		{
			GameObject val = ObjectUtils.LookupPath(Path);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.Error("Savestate stored state on " + Path + ", which does not exist at load time");
				return false;
			}
			val.SetActive(Data.Active);
			return true;
		}
	}
	public class ComponentSnapshot
	{
		public required string Path;

		public required JToken Data;

		public static ComponentSnapshot Of(Component mb)
		{
			return new ComponentSnapshot
			{
				Path = ObjectUtils.ObjectComponentPath(mb),
				Data = SnapshotSerializer.Snapshot(mb)
			};
		}

		public bool Restore()
		{
			Component val = ObjectUtils.LookupObjectComponentPath(Path);
			if (!Object.op_Implicit((Object)(object)val))
			{
				Log.Error("Savestate stored state on " + Path + ", which does not exist at load time");
				return false;
			}
			SnapshotSerializer.Populate(val, Data);
			return true;
		}
	}
	public class GeneralFsmSnapshot
	{
		public required string Path;

		public required string CurrentState;

		public static GeneralFsmSnapshot Of(StateMachineOwner owner)
		{
			return new GeneralFsmSnapshot
			{
				Path = ObjectUtils.ObjectPath(((Component)owner).gameObject),
				CurrentState = ((Object)((StateMachineContext<GeneralState, GeneralState>)(object)owner.FsmContext).fsm.State).name
			};
		}
	}
	public class MonsterLoveFsmSnapshot
	{
		public required string Path;

		public required object CurrentState;

		public static MonsterLoveFsmSnapshot Of(IStateMachine machine)
		{
			return new MonsterLoveFsmSnapshot
			{
				Path = ObjectUtils.ObjectPath(((Component)machine.Component).gameObject),
				CurrentState = machine.CurrentStateMap.stateObj
			};
		}
	}
	public record ReferenceFixupField(string Field, string? Reference);
	public class ReferenceFixups
	{
		public required string Path;

		public required List<ReferenceFixupField> Fields;

		public static ReferenceFixups Of(MonoBehaviour mb, List<ReferenceFixupField> fixups)
		{
			return new ReferenceFixups
			{
				Path = ObjectUtils.ObjectComponentPath((Component)(object)mb),
				Fields = fixups
			};
		}
	}
	public static class SnapshotSerializer
	{
		private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
		{
			ReferenceLoopHandling = (ReferenceLoopHandling)0,
			Error = delegate(object _, ErrorEventArgs args)
			{
				args.ErrorContext.Handled = true;
				Log.Error($"Serialization error while creating snapshot: {args.CurrentObject?.GetType()}: {args.ErrorContext.Path}: {args.ErrorContext.Error.Message}");
			},
			ContractResolver = (IContractResolver)(object)resolver,
			Converters = new List<JsonConverter>
			{
				(JsonConverter)(object)new Vector2Converter(),
				(JsonConverter)(object)new Vector3Converter(),
				(JsonConverter)(object)new Vector4Converter(),
				(JsonConverter)(object)new QuatConverter(),
				(JsonConverter)(object)new ColorConverter(),
				(JsonConverter)(object)new Color32Converter(),
				(JsonConverter)(object)new AnimatorConverter(),
				(JsonConverter)new StringEnumConverter()
			}
		};

		private static CustomizableContractResolver resolver
		{
			get
			{
				CustomizableContractResolver customizableContractResolver = new CustomizableContractResolver();
				customizableContractResolver.ContainerTypesToIgnore = new Type[3]
				{
					typeof(MonoBehaviour),
					typeof(Component),
					typeof(Object)
				};
				customizableContractResolver.FieldTypesToIgnore = new Type[48]
				{
					typeof(PoolObject),
					typeof(MonoBehaviour),
					typeof(Camera),
					typeof(GameObject),
					typeof(UnityEventBase),
					typeof(Action),
					typeof(Delegate),
					typeof(FxPlayer),
					typeof(StateEvents),
					typeof(IEffectOwner),
					typeof(PositionConstraint),
					typeof(PathArea),
					typeof(IEffectHitHandler),
					typeof(ICooldownEffectReceiver),
					typeof(PathToAreaFinder),
					typeof(Value),
					typeof(Sprite),
					typeof(Tilemap),
					typeof(LineRenderer),
					typeof(Color),
					typeof(VelocityModifierParam),
					typeof(ParticleSystem),
					typeof(RopeSegment),
					typeof(AnimationCurve),
					typeof(MultiSpriteEffectController),
					typeof(AnimationClip),
					typeof(IActiveOverrider),
					typeof(CullingObserver),
					typeof(Rect),
					typeof(DelayTask),
					typeof(Tween),
					typeof(RenderTexture),
					typeof(Texture2D),
					typeof(Texture3D),
					typeof(Transform),
					typeof(SpriteRenderer),
					typeof(LayerMask),
					typeof(Collider2D),
					typeof(AbilityWrapper),
					typeof(EffectHitData),
					typeof(DelayPositionData),
					typeof(IStateMachine),
					typeof(RuntimeConditionVote),
					typeof(ScriptableObject),
					typeof(StatData),
					typeof(CharacterStat),
					typeof(StatModifier),
					typeof(MapTileData)
				};
				customizableContractResolver.ExactFieldTypesToIgnore = new Type[4]
				{
					typeof(IResetter),
					typeof(ILevelDestroy),
					typeof(ILevelStart),
					typeof(Component)
				};
				customizableContractResolver.FieldAllowlist = new Dictionary<Type, string[]>
				{
					{
						typeof(Transform),
						new string[3] { "localPosition", "localRotation", "localScale" }
					},
					{
						typeof(Rigidbody2D),
						new string[1] { "position" }
					},
					{
						typeof(ProCamera2D),
						new string[4] { "_cameraTargetHorizontalPositionSmoothed", "_cameraTargetVerticalPositionSmoothed", "_previousCameraTargetHorizontalPositionSmoothed", "_previousCameraTargetVerticalPositionSmoothed" }
					}
				};
				customizableContractResolver.FieldDenylist = new Dictionary<Type, string[]>
				{
					{
						typeof(StealthGameMonster),
						new string[1] { "boxColliderSizes" }
					},
					{
						typeof(FlyingMonster),
						new string[1] { "boxColliderSizes" }
					},
					{
						typeof(MonsterCore),
						new string[1] { "AnimationSpeed" }
					}
				};
				return customizableContractResolver;
			}
		}

		public static void SnapshotRecursive(MonoBehaviour origin, List<ComponentSnapshot> saved, HashSet<Component> seen, int? maxDepth = null, int minDepth = 0, bool onlyDescendants = true)
		{
			MonobehaviourTracing.TraceReferencedMonobehaviours((Component)(object)origin, saved, seen, (Component?)(object)(onlyDescendants ? origin : null), 0, maxDepth, minDepth);
		}

		public static JToken Snapshot(object obj)
		{
			return JToken.FromObject(obj, JsonSerializer.Create(Settings));
		}

		public static string SnapshotToString(object? obj)
		{
			return JsonConvert.SerializeObject(obj, (Formatting)1, Settings);
		}

		public static void Populate(object target, string json)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			JsonReader val = (JsonReader)new JsonTextReader((TextReader)new StringReader(json));
			try
			{
				JsonSerializer.Create(Settings).Populate(val, target);
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		public static void Populate(object target, JToken json)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected O, but got Unknown
			JsonSerializer val = JsonSerializer.Create(Settings);
			JsonReader val2 = (JsonReader)new JTokenReader(json);
			try
			{
				val.Populate(val2, target);
			}
			finally
			{
				((IDisposable)val2)?.Dispose();
			}
		}

		internal static void RemoveNullFields(JToken token, params string[] fields)
		{
			//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)
			JContainer val = (JContainer)(object)((token is JContainer) ? token : null);
			if (val == null)
			{
				return;
			}
			List<JToken> list = new List<JToken>();
			foreach (JToken item in ((JToken)val).Children())
			{
				JProperty val2 = (JProperty)(object)((item is JProperty) ? item : null);
				if (val2 != null && fields.Contains(val2.Name) && val2.Value.ToObject<object>() == null)
				{
					list.Add(item);
				}
				RemoveNullFields(item, fields);
			}
			foreach (JToken item2 in list)
			{
				item2.Remove();
			}
		}
	}
	public static class UiUtils
	{
		public static Texture2D GetColorTexture(Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1);
			val.SetPixel(0, 0, color);
			val.Apply();
			return val;
		}
	}
	internal sealed class MovingAverage
	{
		private readonly int windowSize;

		private readonly Queue<long> samples;

		private long sampleAccumulator;

		public long GetAverage => sampleAccumulator / samples.Count;

		public float GetAverageFloat => (float)sampleAccumulator / (float)samples.Count;

		public MovingAverage(int windowSize = 30)
		{
			this.windowSize = windowSize;
			samples = new Queue<long>(this.windowSize + 1);
		}

		public void Clear()
		{
			sampleAccumulator = 0L;
			samples.Clear();
		}

		public void Sample(long newSample)
		{
			sampleAccumulator += newSample;
			samples.Enqueue(newSample);
			if (samples.Count > windowSize)
			{
				sampleAccumulator -= samples.Dequeue();
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "DebugModPlus";

		public const string PLUGIN_NAME = "DebugModPlus";

		public const string PLUGIN_VERSION = "1.10.0";
	}
}
namespace DebugModPlus.Utils
{
	public static class Extensions
	{
		public static IEnumerable<AttackSensor> AttackSensorsCompat(this MonsterBase monsterBase)
		{
			FieldInfo field = typeof(MonsterBase).GetField("attackSensors", BindingFlags.Instance | BindingFlags.Public);
			if (field != null)
			{
				return (List<AttackSensor>)field.GetValue(monsterBase);
			}
			return (AttackSensor[])typeof(MonsterBase).GetField("_attackSensors", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(monsterBase);
		}
	}
	public static class StateMachineExtensions
	{
		private static FieldRef<FSMStateMachineRunner, List<IStateMachine>> stateMachineRunnerStateMachineList = AccessTools.FieldRefAccess<FSMStateMachineRunner, List<IStateMachine>>("stateMachineList");

		private static FieldRef<AbstractStateTransition, AbstractConditionComp[]> stateTransitionConditions = AccessTools.FieldRefAccess<AbstractStateTransition, AbstractConditionComp[]>("conditions");

		public static AbstractConditionComp[] Conditions(this AbstractStateTransition transition)
		{
			return stateTransitionConditions.Invoke(transition);
		}

		public static List<IStateMachine> GetMachines(this FSMStateMachineRunner runner)
		{
			return stateMachineRunnerStateMachineList.Invoke(runner);
		}

		public static IEnumerable<(object, MappingState)> GetStates(this IStateMachine machine)
		{
			return ReflectionExtension.GetFieldValue<IList>(ReflectionExtension.GetFieldValue<object>((object)machine, "_stateMapping"), "mappingList").Cast<object>().Select(delegate(object stateObj)
			{
				object fieldValue = ReflectionExtension.GetFieldValue<object>(stateObj, "state");
				MappingState fieldValue2 = ReflectionExtension.GetFieldValue<MappingState>(stateObj, "stateBehavior");
				return (fieldValue, fieldValue2);
			});
		}
	}
}
namespace DebugModPlus.Savestates
{
	[PublicAPI]
	public class CustomizableContractResolver : DefaultContractResolver
	{
		public BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public BindingFlags PropertyBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public Dictionary<Type, string[]> FieldAllowlist = new Dictionary<Type, string[]>();

		public Dictionary<Type, string[]> FieldDenylist = new Dictionary<Type, string[]>();

		public Type[] ContainerTypesToIgnore = Array.Empty<Type>();

		public Type[] FieldTypesToIgnore = Array.Empty<Type>();

		public Type[] ExactFieldTypesToIgnore = Array.Empty<Type>();

		protected override List<MemberInfo> GetSerializableMembers(Type objectType)
		{
			List<MemberInfo> list = new List<MemberInfo>();
			Type ty = objectType;
			while (ty != typeof(object) && ty != null)
			{
				Type key = (ty.IsGenericType ? ty.GetGenericTypeDefinition() : ty);
				if (FieldAllowlist.TryGetValue(key, out string[] value))
				{
					list.AddRange(value.Select(delegate(string fieldName)
					{
						object obj = ((object)ty.GetField(fieldName, FieldBindingFlags | BindingFlags.DeclaredOnly)) ?? ((object)ty.GetProperty(fieldName, PropertyBindingFlags | BindingFlags.DeclaredOnly));
						if ((MemberInfo?)obj == null)
						{
							Log.Error($"Field '{fieldName}' in allowlist of '{ty}' does not exist!");
						}
						return (MemberInfo)obj;
					}).Cast<MemberInfo>());
				}
				else
				{
					list.AddRange(from field in ty.GetFields(FieldBindingFlags | BindingFlags.DeclaredOnly)
						where field.GetCustomAttribute<CompilerGeneratedAttribute>() == null
						select field);
					list.AddRange(ty.GetProperties(PropertyBindingFlags | BindingFlags.DeclaredOnly).Where(delegate(PropertyInfo prop)
					{
						if (prop.CanWrite && prop.CanRead)
						{
							MethodInfo getMethod = prop.GetGetMethod();
							if ((object)getMethod == null || !getMethod.IsVirtual)
							{
								return ((MemberInfo)prop).GetCustomAttribute<NativePropertyAttribute>() != null;
							}
							return true;
						}
						return false;
					}));
				}
				ty = ty.BaseType;
			}
			if (FieldDenylist.TryGetValue(objectType, out string[] denyList))
			{
				list.RemoveAll((MemberInfo field) => denyList.Contains(field.Name));
			}
			return list;
		}

		protected override JsonContract CreateContract(Type objectType)
		{
			if (objectType == typeof(Transform))
			{
				return (JsonContract)(object)((DefaultContractResolver)this).CreateObjectContract(objectType);
			}
			return ((DefaultContractResolver)this).CreateContract(objectType);
		}

		private bool IgnorePropertyType(Type? type)
		{
			Type type2 = type;
			if (!Array.Exists(ExactFieldTypesToIgnore, (Type x) => x == type2))
			{
				return Array.Exists(FieldTypesToIgnore, (Type x) => x.IsAssignableFrom(type2));
			}
			return true;
		}

		protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
		{
			JsonProperty val = ((DefaultContractResolver)this).CreateProperty(member, (MemberSerialization)2);
			val.Ignored = false;
			bool shouldSerialize = true;
			Type propertyType = val.PropertyType;
			if (propertyType == null)
			{
				return val;
			}
			shouldSerialize &= !IgnorePropertyType(propertyType);
			if (propertyType.IsArray)
			{
				shouldSerialize &= !IgnorePropertyType(propertyType.GetElementType());
			}
			if (propertyType.IsGenericType)
			{
				if (propertyType.GetGenericTypeDefinition() == typeof(List<>))
				{
					shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[0]);
					val.ObjectCreationHandling = (ObjectCreationHandling)2;
				}
				if (propertyType.GetGenericTypeDefinition() == typeof(Dictionary<, >))
				{
					Type[] genericArguments = propertyType.GetGenericArguments();
					shouldSerialize &= genericArguments[0].IsPrimitive || genericArguments[0] == typeof(string);
					shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[1]);
				}
				if (propertyType.GetGenericTypeDefinition() == typeof(HashSet<>))
				{
					shouldSerialize &= !IgnorePropertyType(propertyType.GetGenericArguments()[0]);
				}
			}
			if (ContainerTypesToIgnore.Contains<Type>(member.DeclaringType))
			{
				shouldSerialize = false;
			}
			val.ShouldSerialize = (object _) => shouldSerialize;
			return val;
		}
	}
	public class MappingConverter<T, TU> : JsonConverter<T>
	{
		[CompilerGenerated]
		private Func<T, TU> <func>P;

		public MappingConverter(Func<T, TU> func)
		{
			<func>P = func;
			base..ctor();
		}

		public override void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer)
		{
			serializer.Serialize(writer, (value == null) ? "null" : ((object)<func>P(value)));
		}

		public override T ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer)
		{
			throw new NotImplementedException();
		}
	}
	public abstract class NullableJsonConverter<T> : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (value == null)
			{
				writer.WriteNull();
			}
			else
			{
				WriteJson(writer, (T)value, serializer);
			}
		}

		protected abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if (existingValue != null && !(existingValue is T))
			{
				throw new JsonSerializationException($"Converter cannot read JSON with the specified existing value. {typeof(T)} is required.");
			}
			return ReadJson(reader, objectType, (existingValue == null) ? default(T) : ((T)existingValue), existingValue != null, serializer);
		}

		protected abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);

		public sealed override bool CanConvert(Type objectType)
		{
			Type c = Nullable.GetUnderlyingType(objectType) ?? objectType;
			return typeof(T).IsAssignableFrom(c);
		}
	}
	public abstract class NullableJsonConverter : JsonConverter
	{
		public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (value == null)
			{
				writer.WriteNull();
			}
			else
			{
				WriteJsonInner(writer, value, serializer);
			}
		}

		protected abstract void WriteJsonInner(JsonWriter writer, object value, JsonSerializer serializer);

		public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (existingValue != null)
			{
				throw new JsonSerializationException("Converter cannot read JSON with the specified existing value.");
			}
			return ReadJsonInner(reader, objectType, existingValue, serializer);
		}

		protected abstract object? ReadJsonInner(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);

		protected abstract bool CanConvertInner(Type objectType);

		public sealed override bool CanConvert(Type objectType)
		{
			Type objectType2 = Nullable.GetUnderlyingType(objectType) ?? objectType;
			return CanConvertInner(objectType2);
		}
	}
	public class EnumConverter : NullableJsonConverter
	{
		public static string EnumToString(object value)
		{
			string? fullName = value.GetType().FullName;
			string name = Enum.GetName(value.GetType(), value);
			return fullName + "." + name;
		}

		protected override void WriteJsonInner(JsonWriter writer, object? value, JsonSerializer serializer)
		{
			if (value == null)
			{
				writer.WriteNull();
			}
			else
			{
				writer.WriteValue(EnumToString(value));
			}
		}

		protected override object ReadJsonInner(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
		{
			throw new NotImplementedException();
		}

		protected override bool CanConvertInner(Type objectType)
		{
			return objectType.IsEnum;
		}
	}
	public static class FlagLogic
	{
		public static void LoadFlags(JObject newFlags, GameFlagCollection allFlags)
		{
			foreach (KeyValuePair<string, GameFlagBase> item in allFlags.flagDict)
			{
				item.Deconstruct(out var key, out var value);
				string text = key;
				GameFlagBase val = value;
				JToken obj = newFlags[text];
				JObject val2 = (JObject)(object)((obj is JObject) ? obj : null);
				if (val2 == null)
				{
					continue;
				}
				foreach (KeyValuePair<string, FlagFieldBase> fieldCache in val.fieldCaches)
				{
					fieldCache.Deconstruct(out key, out var value2);
					string text2 = key;
					FlagFieldBase val3 = value2;
					JToken val4 = val2[text2];
					if (val4 == null)
					{
						continue;
					}
					FlagFieldBool val5 = (FlagFieldBool)(object)((val3 is FlagFieldBool) ? val3 : null);
					if (val5 == null)
					{
						FlagFieldInt val6 = (FlagFieldInt)(object)((val3 is FlagFieldInt) ? val3 : null);
						if (val6 == null)
						{
							FlagFieldString val7 = (FlagFieldString)(object)((val3 is FlagFieldString) ? val3 : null);
							if (val7 == null)
							{
								FlagFieldFloat val8 = (FlagFieldFloat)(object)((val3 is FlagFieldFloat) ? val3 : null);
								if (val8 == null)
								{
									FlagFieldLong val9 = (FlagFieldLong)(object)((val3 is FlagFieldLong) ? val3 : null);
									if (val9 != null)
									{
										((FlagField<long>)(object)val9).CurrentValue = Extensions.Value<long>((IEnumerable<JToken>)val4);
									}
								}
								else
								{
									((FlagField<float>)(object)val8).CurrentValue = Extensions.Value<float>((IEnumerable<JToken>)val4);
								}
							}
							else
							{
								((FlagField<string>)(object)val7).CurrentValue = Extensions.Value<string>((IEnumerable<JToken>)val4);
							}
						}
						else
						{
							((FlagField<int>)(object)val6).CurrentValue = Extensions.Value<int>((IEnumerable<JToken>)val4);
						}
					}
					else
					{
						((FlagField<bool>)(object)val5).CurrentValue = Extensions.Value<bool>((IEnumerable<JToken>)val4);
					}
				}
			}
		}
	}
	internal static class MonobehaviourTracing
	{
		private static readonly Type[] FindReferenceIgnoreList = new Type[17]
		{
			typeof(Transform),
			typeof(EffectDealer),
			typeof(GameLevel),
			typeof(PositionConstraint),
			typeof(PlayerInputCommandQueue),
			typeof(HackDrone),
			typeof(SpriteFlasher),
			typeof(PoolObject),
			typeof(PathArea),
			typeof(DamageScalarSource),
			typeof(PathToAreaFinder),
			typeof(MultiSpriteEffectController),
			typeof(IOnEnableInvokable),
			typeof(OnEnableHierarchyInvoker),
			typeof(EffectReceiver),
			typeof(SoundEmitter),
			typeof(SoundEmitter)
		};

		private static readonly Type[] FindReferenceIgnoreListBase = new Type[5]
		{
			typeof(IAbstractEventReceiver),
			typeof(ILevelResetPrepare),
			typeof(ILevelResetStart),
			typeof(Renderer),
			typeof(Collider2D)
		};

		public static void TraceReferencedMonobehaviours(Component origin, List<ComponentSnapshot> saved, HashSet<Component> seen, Component? onlyDescendantsOf, int depth = 0, int? maxDepth = null, int minDepth = 0)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Expected O, but got Unknown
			Scene scene = origin.gameObject.scene;
			if (!((Scene)(ref scene)).IsValid() || seen.Contains(origin))
			{
				return;
			}
			if (depth >= minDepth)
			{
				saved.Add(ComponentSnapshot.Of(origin));
			}
			seen.Add(origin);
			if (depth >= maxDepth)
			{
				return;
			}
			FieldInfo[] fields = ((object)origin).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo field in fields)
			{
				if (FindReferenceIgnoreList.Contains(field.FieldType) || Array.Exists(FindReferenceIgnoreListBase, (Type x) => x.IsAssignableFrom(field.FieldType)))
				{
					continue;
				}
				if (field.FieldType.IsArray)
				{
					Type elementType = field.FieldType.GetElementType();
					if (!typeof(Component).IsAssignableFrom(elementType))
					{
						continue;
					}
					Component[] array = (Component[])field.GetValue(origin);
					foreach (Component val in array)
					{
						if (Object.op_Implicit((Object)(object)val))
						{
							if (!Object.op_Implicit((Object)(object)onlyDescendantsOf))
							{
								TraceReferencedMonobehaviours(val, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth);
							}
							else if (val.transform.IsChildOf(onlyDescendantsOf.transform))
							{
								TraceReferencedMonobehaviours(val, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth);
							}
							else if (!seen.Contains(val))
							{
								Log.Info($"Skipping {val}: not child of {onlyDescendantsOf}");
							}
						}
					}
				}
				if (!typeof(Component).IsAssignableFrom(field.FieldType))
				{
					continue;
				}
				Component val2 = (Component)field.GetValue(origin);
				if (Object.op_Implicit((Object)(object)val2))
				{
					if (!Object.op_Implicit((Object)(object)onlyDescendantsOf))
					{
						TraceReferencedMonobehaviours(val2, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth);
					}
					else if (val2.transform.IsChildOf(onlyDescendantsOf.transform))
					{
						TraceReferencedMonobehaviours(val2, saved, seen, onlyDescendantsOf, depth + 1, maxDepth, minDepth);
					}
					else if (!seen.Contains(val2))
					{
						Log.Info($"Skipping {val2}: not child of {onlyDescendantsOf}");
					}
				}
			}
		}
	}
	[HarmonyPatch]
	public class Patches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Actor), "OnRebindAnimatorMove")]
		[HarmonyPatch(typeof(Player), "OnRebindAnimatorMove")]
		[HarmonyPatch(typeof(MonsterBase), "OnRebindAnimatorMove")]
		public static bool PreventDuringLoad(MethodBase __originalMethod)
		{
			return !DebugModPlusInterop.IsLoadingSavestate;
		}
	}
	[Flags]
	public enum SavestateFilter
	{
		None = 0,
		Flags = 2,
		Player = 4,
		Monsters = 8,
		FSMs = 0x10,
		All = 0x1E
	}
	[Flags]
	public enum SavestateLoadMode
	{
		None = 0,
		ResetScene = 1,
		ReloadScene = 2
	}
	public static class SavestateLogic
	{
		public static Savestate Create(SavestateFilter filter)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Unknown result type (might be due to invalid IL or missing references)
			if (!SingletonBehaviour<GameCore>.IsAvailable())
			{
				throw new Exception("Can't create savestate outside of game level");
			}
			GameCore instance = SingletonBehaviour<GameCore>.Instance;
			if (!Object.op_Implicit((Object)(object)instance.gameLevel))
			{
				throw new Exception("Can't create savestate outside of game level");
			}
			Player i = Player.i;
			List<ComponentSnapshot> list = new List<ComponentSnapshot>();
			List<GameObjectSnapshot> list2 = new List<GameObjectSnapshot>();
			List<MonsterLoveFsmSnapshot> list3 = new List<MonsterLoveFsmSnapshot>();
			List<GeneralFsmSnapshot> list4 = new List<GeneralFsmSnapshot>();
			List<ReferenceFixups> list5 = new List<ReferenceFixups>();
			JObject val = new JObject();
			HashSet<Component> seen = new HashSet<Component>();
			if (filter.HasFlag(SavestateFilter.Player))
			{
				list.Add(ComponentSnapshot.Of((Component)(object)((Component)i).transform));
				list2.Add(GameObjectSnapshot.Of(((Component)i.pushAwayCollider).gameObject));
				SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)i, list, seen);
				foreach (var state in ((IStateMachine)(object)i.fsm).GetStates())
				{
					SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)state.Item2, list, seen, 0);
				}
				SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)SingletonBehaviour<CameraManager>.Instance.camera2D, list, seen, 0);
			}
			if (filter.HasFlag(SavestateFilter.Monsters))
			{
				MonsterBase[] array = Object.FindObjectsOfType<MonsterBase>();
				foreach (MonsterBase val2 in array)
				{
					list.Add(ComponentSnapshot.Of((Component)(object)((Component)val2).transform));
					SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)val2, list, seen);
					list3.Add(MonsterLoveFsmSnapshot.Of((IStateMachine)(object)val2.fsm));
					AttackSensor[] attackSensors = val2.attackSensors;
					for (int k = 0; k < attackSensors.Length; k++)
					{
						SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)attackSensors[k], list, seen);
					}
					foreach (var state2 in ((IStateMachine)(object)val2.fsm).GetStates())
					{
						SnapshotSerializer.SnapshotRecursive((MonoBehaviour)(object)state2.Item2, list, seen);
					}
				}
			}
			if (filter.HasFlag(SavestateFilter.FSMs))
			{
				StateMachineOwner[] array2 = Object.FindObjectsOfType<StateMachineOwner>();
				foreach (StateMachineOwner owner in array2)
				{
					list4.Add(GeneralFsmSnapshot.Of(owner));
				}
			}
			if (filter.HasFlag(SavestateFilter.Player))
			{
				list3.Add(MonsterLoveFsmSnapshot.Of((IStateMachine)(object)i.fsm));
				list5.Add(ReferenceFixups.Of((MonoBehaviour)(object)Player.i, new List<ReferenceFixupField>(1)
				{
					new ReferenceFixupField("touchingRope", ObjectUtils.ObjectComponentPath((Component)(object)Player.i.touchingRope))
				}));
			}
			if (filter.HasFlag(SavestateFilter.Flags))
			{
				val = JObject.Parse(GameFlagManager.FlagsToJson(SingletonBehaviour<SaveManager>.Instance.allFlags));
			}
			Savestate obj = new Savestate
			{
				Flags = ((((JContainer)val).Count == 0) ? null : val)
			};
			Scene scene = ((Component)instance.gameLevel).gameObject.scene;
			obj.Scene = ((Scene)(ref scene)).name;
			obj.PlayerPosition = ((Component)i).transform.position;
			obj.LastTeleportId = ((GameFlagBase)SingletonBehaviour<ApplicationCore>.Instance.lastSaveTeleportPoint).FinalSaveID;
			obj.MonobehaviourSnapshots = list;
			obj.GameObjectSnapshots = list2;
			obj.FsmSnapshots = ((list3.Count == 0) ? null : list3);
			obj.GeneralFsmSnapshots = ((list4.Count == 0) ? null : list4);
			obj.ReferenceFixups = ((list5.Count == 0) ? null : list5);
			obj.RandomState = Random.state;
			return obj;
		}

		public static async Task Load(Savestate savestate, SavestateLoadMode loadMode)
		{
			try
			{
				DebugModPlusInterop.IsLoadingSavestate = true;
				await LoadInner(savestate, loadMode);
			}
			finally
			{
				DebugModPlusInterop.IsLoadingSavestate = false;
			}
		}

		private static async Task LoadInner(Savestate savestate, SavestateLoadMode loadMode)
		{
			if (!SingletonBehaviour<GameCore>.IsAvailable())
			{
				throw new Exception("Attempted to load savestate outside of scene");
			}
			if (savestate.LastTeleportId != null)
			{
				TeleportPointData teleportPointWithPath = SingletonBehaviour<GameFlagManager>.Instance.GetTeleportPointWithPath(savestate.LastTeleportId);
				SingletonBehaviour<ApplicationCore>.Instance.lastSaveTeleportPoint = teleportPointWithPath;
			}
			Stopwatch sw = Stopwatch.StartNew();
			sw.Start();
			JObject flags = savestate.Flags;
			if (flags != null)
			{
				FlagLogic.LoadFlags(flags, SingletonBehaviour<SaveManager>.Instance.allFlags);
				Log.Debug($"- Applied flags in {sw.ElapsedMilliseconds}ms");
				SingletonBehaviour<SaveManager>.Instance.allFlags.AllFlagInitStartAndEquip();
			}
			if (SingletonBehaviour<DialoguePlayer>.Instance.CanSkip)
			{
				SingletonBehaviour<DialoguePlayer>.Instance.ForceClose();
			}
			string? scene = savestate.Scene;
			GameLevel gameLevel = SingletonBehaviour<GameCore>.Instance.gameLevel;
			bool flag = scene == ((gameLevel != null) ? gameLevel.SceneName : null);
			if (savestate.Scene != null)
			{
				if ((savestate.Scene != null && !flag) || loadMode.HasFlag(SavestateLoadMode.ReloadScene))
				{
					Vector3 playerPosition = savestate.PlayerPosition ?? throw new Exception("Savestate with scene must have `playerPosition`");
					sw.Restart();
					Task task = ChangeSceneAsync(new ChangeSceneData
					{
						sceneName = savestate.Scene,
						playerSpawnPosition = (SpawnPositionDelegate)(() => playerPosition)
					});
					if (await Task.WhenAny(new Task[2]
					{
						task,
						Task.Delay(5000)
					}) != task)
					{
						ToastManager.Toast((object)"Savestate was not loaded after 5s, aborting");
						return;
					}
					Log.Info($"- Change scene in {sw.ElapsedMilliseconds}ms");
				}
			}
			else
			{
				Vector3? playerPosition2 = savestate.PlayerPosition;
				if (playerPosition2.HasValue)
				{
					Vector3 valueOrDefault = playerPosition2.GetValueOrDefault();
					((Component)Player.i).transform.position = valueOrDefault;
				}
			}
			if (loadMode.HasFlag(SavestateLoadMode.ResetScene))
			{
				SingletonBehaviour<GameCore>.Instance.ResetLevel(false);
			}
			sw.Restart();
			if (savestate.MonobehaviourSnapshots != null)
			{
				foreach (ComponentSnapshot monobehaviourSnapshot in savestate.MonobehaviourSnapshots)
				{
					monobehaviourSnapshot.Restore();
				}
				Log.Info($"- Applied snapshots to scene in {sw.ElapsedMilliseconds}ms");
			}
			sw.Stop();
			foreach (GameObjectSnapshot item in savestate.GameObjectSnapshots ?? new List<GameObjectSnapshot>())
			{
				item.Restore();
			}
			if (savestate.ReferenceFixups != null)
			{
				ApplyFixups(savestate.ReferenceFixups);
			}
			foreach (MonsterLoveFsmSnapshot item2 in savestate.FsmSnapshots ?? new List<MonsterLoveFsmSnapshot>())
			{
				GameObject val = ObjectUtils.LookupPath(item2.Path);
				if ((Object)(object)val == (Object)null)
				{
					Log.Error("Savestate stored monsterlove fsm state on " + item2.Path + ", which does not exist at load time");
					continue;
				}
				FSMStateMachineRunner component = val.GetComponent<FSMStateMachineRunner>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					Log.Error("Savestate stored monsterlove fsm state on " + item2.Path + ", which has no FSMStateMachineRunner");
					continue;
				}
				foreach (IStateMachine machine in component.GetMachines())
				{
					object stateObj = Enum.ToObject(machine.CurrentStateMap.stateObj.GetType(), item2.CurrentState);
					EnterStateDirectly(machine, stateObj);
				}
			}
			foreach (GeneralFsmSnapshot fsm in savestate.GeneralFsmSnapshots ?? new List<GeneralFsmSnapshot>())
			{
				GameObject val2 = ObjectUtils.LookupPath(fsm.Path);
				if ((Object)(object)val2 == (Object)null)
				{
					Log.Error("Savestate stored general fsm state on " + fsm.Path + ", which does not exist at load time");
					continue;
				}
				StateMachineOwner component2 = val2.GetComponent<StateMachineOwner>();
				if (!Object.op_Implicit((Object)(object)component2))
				{
					Log.Error("Savestate stored general fsm state on " + fsm.Path + ", which has no FSMStateMachineRunner");
					continue;
				}
				GeneralState val3 = ((IEnumerable<GeneralState>)((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).States).FirstOrDefault((Func<GeneralState, bool>)((GeneralState state) => ((Object)state).name == fsm.CurrentState));
				if (!Object.op_Implicit((Object)(object)val3))
				{
					Log.Error("State " + fsm.CurrentState + " does not exist on " + fsm.Path);
					continue;
				}
				try
				{
					((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).ChangeState(val3);
				}
				catch (Exception arg)
				{
					Log.Error($"Could not apply fsm state on {component2.FsmContext}/{((StateMachineContext<GeneralState, GeneralState>)(object)component2.FsmContext).fsm} {arg}");
				}
			}
			Player.i.playerInput.RevokeAllMyVote((MonoBehaviour)(object)Player.i.PlayerDeadState);
			Tween.StopAll((object)null);
			BossArea[] array = Object.FindObjectsOfType<BossArea>();
			for (int i = 0; i < array.Length; i++)
			{
				array[i].ForceShowHP();
			}
			foreach (RuntimeConditionVote item3 in ReflectionExtension.GetFieldValue<List<RuntimeConditionVote>>((object)Player.i.playerInput, "conditionVoteList"))
			{
				item3.votes.Clear();
				item3.ManualUpdate();
			}
			State? randomState = savestate.RandomState;
			if (randomState.HasValue)
			{
				State valueOrDefault2 = randomState.GetValueOrDefault();
				Random.state = valueOrDefault2;
			}
			Player.i.UpdateSpriteFacing();
		}

		private static void ApplyFixups(List<ReferenceFixups> fixups)
		{
			foreach (ReferenceFixups fixup in fixups)
			{
				Component val = ObjectUtils.LookupObjectComponentPath(fixup.Path);
				if ((Object)(object)val == (Object)null)
				{
					Log.Error("Savestate stored reference fixup on " + fixup.Path + ", which does not exist at load time");
					continue;
				}
				foreach (ReferenceFixupField field2 in fixup.Fields)
				{
					field2.Deconstruct(out string Field, out string Reference);
					string text = Field;
					string text2 = Reference;
					FieldInfo field = ((object)val).GetType().GetField(text, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (text2 == null)
					{
						field.SetValue(val, null);
						continue;
					}
					Component val2 = ObjectUtils.LookupObjectComponentPath(text2);
					if ((Object)(object)val2 == (Object)null)
					{
						Log.Error("Savestate stored reference fixup on " + fixup.Path + "." + text + ", but the target " + text2 + " does not exist at load time");
					}
					else
					{
						field.SetValue(val, val2);
					}
				}
			}
		}

		private static void EnterStateDirectly(IStateMachine sm, object stateObj)
		{
			FSMStateMachineRunner fieldValue = ReflectionExtension.GetFieldValue<FSMStateMachineRunner>((object)sm, "engine");
			IDictionary fieldValue2 = ReflectionExtension.GetFieldValue<IDictionary>((object)sm, "stateLookup");
			if (!fieldValue2.Contains(stateObj))
			{
				throw new Exception($"state {stateObj} not found in fsm");
			}
			object value = fieldValue2[stateObj];
			Type type = ((object)sm).GetType();
			FieldInfo fieldInfo = ReflectionExtension.GetFieldInfo(type, "queuedChange", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true);
			FieldInfo fieldInfo2 = ReflectionExtension.GetFieldInfo(type, "currentTransition", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true);
			FieldInfo fieldInfo3 = ReflectionExtension.GetFieldInfo(type, "exitRoutine", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, true);
			FieldInfo fieldInfo4 = ReflectionExtension.GetFie