Decompiled source of SSManager v1.0.1

BepInEx/plugins/SilksongManager.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GlobalEnums;
using HarmonyLib;
using HutongGames.PlayMaker;
using InControl;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SilksongManager.Currency;
using SilksongManager.Damage;
using SilksongManager.DebugMenu;
using SilksongManager.DebugMenu.Windows;
using SilksongManager.Enemies;
using SilksongManager.Hitbox;
using SilksongManager.Inventory;
using SilksongManager.Menu;
using SilksongManager.Menu.Keybinds;
using SilksongManager.Patches;
using SilksongManager.Player;
using SilksongManager.SaveState;
using SilksongManager.SpeedControl;
using SilksongManager.Tools;
using SilksongManager.UI;
using SilksongManager.World;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[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("Catalyst")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Debug and utility mod for Hollow Knight: Silksong")]
[assembly: AssemblyFileVersion("1.0.0.2")]
[assembly: AssemblyInformationalVersion("1.0.0.2+022e1c75a2848601392bf2bdbce105a3328b5d21")]
[assembly: AssemblyProduct("SilksongManager")]
[assembly: AssemblyTitle("SilksongManager")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.2")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SilksongManager
{
	[BepInPlugin("ru.catalyst.silksongmanager", "Silksong Manager", "1.0.0.2")]
	public class Plugin : BaseUnityPlugin
	{
		private DebugMenuController _debugMenu;

		private bool _menuHookInitialized;

		private bool _enemiesFrozen;

		public static ManualLogSource Log { get; private set; }

		public static Plugin Instance { get; private set; }

		public static PluginConfig ModConfig { get; private set; }

		public static PlayerData PD => PlayerData.instance;

		public static HeroController Hero => HeroController.instance;

		public static GameManager GM => GameManager.instance;

		public static UIManager UI => UIManager.instance;

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Silksong Manager v1.0.0.2 loading...");
			InitializeConfiguration();
			InitializeSystems();
			InitializePatches();
			SceneManager.sceneLoaded += OnSceneLoaded;
			Log.LogInfo((object)"Silksong Manager initialized successfully!");
		}

		private void Update()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleDebugMenu))
			{
				_debugMenu?.ToggleMenu();
			}
			HandleHotkeys();
		}

		private void LateUpdate()
		{
			CheatSystem.Update();
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			Log.LogInfo((object)"Silksong Manager unloaded.");
		}

		private void InitializeConfiguration()
		{
			ModConfig = new PluginConfig(((BaseUnityPlugin)this).Config);
			ModKeybindManager.Initialize(((BaseUnityPlugin)this).Config);
		}

		private void InitializeSystems()
		{
			CheatSystem.Initialize(((BaseUnityPlugin)this).Config);
			DamageSystem.Initialize(((BaseUnityPlugin)this).Config);
			_debugMenu = ((Component)this).gameObject.AddComponent<DebugMenuController>();
			((Component)this).gameObject.AddComponent<NotificationManager>();
			HitboxManager.Initialize(((Component)this).gameObject);
			SaveStateManager.Initialize();
			SpeedControlManager.Initialize();
		}

		private void InitializePatches()
		{
			DamagePatches.Apply();
		}

		private void HandleHotkeys()
		{
			if (ModConfig.EnableHotkeys)
			{
				HandleMovementHotkeys();
				HandleCombatHotkeys();
				HandleResourceHotkeys();
				HandleGameSpeedHotkeys();
				HandleDebugHotkeys();
				HandleSaveStateHotkeys();
				HandleSceneHotkeys();
			}
		}

		private void HandleMovementHotkeys()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleNoclip))
			{
				CheatSystem.ToggleNoclip();
				bool noclipEnabled = CheatSystem.NoclipEnabled;
				NotificationManager.Show("Noclip", noclipEnabled ? "ON" : "OFF");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.SavePosition))
			{
				WorldActions.SavePosition();
				HeroController hero = Hero;
				Vector3 val = ((hero != null) ? ((Component)hero).transform.position : Vector3.zero);
				NotificationManager.Show("Position Saved", $"X: {val.x:F1}, Y: {val.y:F1}");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.LoadPosition))
			{
				WorldActions.LoadPosition();
				NotificationManager.Show("Position Loaded");
			}
		}

		private void HandleCombatHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleInvincibility))
			{
				PlayerActions.ToggleInvincibility();
				bool flag = PD?.isInvincible ?? false;
				NotificationManager.Show("Invincibility", flag ? "ON" : "OFF");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleInfiniteJumps))
			{
				CheatSystem.ToggleInfiniteJumps();
				bool infiniteJumps = CheatSystem.InfiniteJumps;
				NotificationManager.Show("Infinite Jumps", infiniteJumps ? "ON" : "OFF");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleInfiniteHealth))
			{
				CheatSystem.ToggleInfiniteHealth();
				bool infiniteHealth = CheatSystem.InfiniteHealth;
				NotificationManager.Show("Infinite Health", infiniteHealth ? "ON" : "OFF");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleInfiniteSilk))
			{
				CheatSystem.ToggleInfiniteSilk();
				bool infiniteSilk = CheatSystem.InfiniteSilk;
				NotificationManager.Show("Infinite Silk", infiniteSilk ? "ON" : "OFF");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.KillAllEnemies))
			{
				int enemyCount = EnemyActions.GetEnemyCount();
				EnemyActions.KillAllEnemies();
				NotificationManager.Show("Kill All Enemies", $"{enemyCount} enemies killed");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.FreezeEnemies))
			{
				_enemiesFrozen = !_enemiesFrozen;
				if (_enemiesFrozen)
				{
					EnemyActions.FreezeAllEnemies();
				}
				else
				{
					EnemyActions.UnfreezeAllEnemies();
				}
				NotificationManager.Show("Freeze Enemies", _enemiesFrozen ? "ON" : "OFF");
			}
		}

		private void HandleResourceHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.AddGeo))
			{
				CurrencyActions.AddGeo(1000);
				NotificationManager.Show("+1000 Geo", $"Total: {PD?.geo ?? 0}");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.AddShellShards))
			{
				CurrencyActions.AddShards(5);
				NotificationManager.Show("+5 Shell Shards");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.MaxSilk))
			{
				PlayerActions.QuickSilk();
				NotificationManager.Show("Max Silk");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.HealToFull))
			{
				PlayerActions.QuickHeal();
				NotificationManager.Show("Full Health");
			}
		}

		private void HandleGameSpeedHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.IncreaseGameSpeed))
			{
				SpeedControlManager.SetGlobalSpeed(SpeedControlConfig.GlobalSpeed + 0.25f);
				NotificationManager.Show("Game Speed", $"{SpeedControlConfig.GlobalSpeed:F2}x");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.DecreaseGameSpeed))
			{
				SpeedControlManager.SetGlobalSpeed(Mathf.Max(0.1f, SpeedControlConfig.GlobalSpeed - 0.25f));
				NotificationManager.Show("Game Speed", $"{SpeedControlConfig.GlobalSpeed:F2}x");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.ResetGameSpeed))
			{
				SpeedControlManager.ResetAll();
				NotificationManager.Show("Game Speed", "1.0x (Reset)");
			}
		}

		private void HandleDebugHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.ToggleHitboxes))
			{
				HitboxManager.ToggleHitboxes();
				bool showHitboxes = HitboxConfig.ShowHitboxes;
				NotificationManager.Show("Hitboxes", showHitboxes ? "ON" : "OFF");
			}
		}

		private void HandleSaveStateHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.SaveState))
			{
				string text = SaveStateManager.QuickSave();
				NotificationManager.Show("State Saved", "\"" + text + "\"");
			}
			if (ModKeybindManager.WasActionPressed(ModAction.LoadLastState))
			{
				string text2 = SaveStateManager.LoadLastState();
				if (text2 != null)
				{
					NotificationManager.Show("Loading State", "\"" + text2 + "\"");
				}
				else
				{
					NotificationManager.Show("No States", "Save a state first");
				}
			}
		}

		private void HandleSceneHotkeys()
		{
			if (ModKeybindManager.WasActionPressed(ModAction.ReloadScene))
			{
				string text = WorldActions.ReloadCurrentScene();
				if (text != null)
				{
					NotificationManager.Show("Reload Scene", text);
				}
			}
			if (ModKeybindManager.WasActionPressed(ModAction.Respawn))
			{
				WorldActions.Respawn();
				NotificationManager.Show("Respawn");
			}
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			Log.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name));
			if (((Scene)(ref scene)).name == "Menu_Title")
			{
				((MonoBehaviour)this).StartCoroutine(WaitForMainMenuAndInitialize());
				return;
			}
			_menuHookInitialized = false;
			MainMenuHook.Reset();
		}

		private IEnumerator WaitForMainMenuAndInitialize()
		{
			float timeout = 10f;
			float elapsed = 0f;
			Log.LogInfo((object)"Waiting for MainMenuOptions to appear...");
			for (; elapsed < timeout; elapsed += 0.1f)
			{
				if ((Object)(object)Object.FindAnyObjectByType<MainMenuOptions>() != (Object)null)
				{
					Log.LogInfo((object)$"MainMenuOptions found after {elapsed:F2}s");
					if (!_menuHookInitialized)
					{
						MainMenuHook.Initialize();
						_menuHookInitialized = true;
					}
					yield break;
				}
				yield return (object)new WaitForSeconds(0.1f);
			}
			Log.LogWarning((object)$"MainMenuOptions not found after {timeout}s timeout!");
		}
	}
	public class PluginConfig
	{
		private readonly ConfigFile _config;

		private ConfigEntry<bool> _enableHotkeys;

		private ConfigEntry<bool> _showDebugInfo;

		private ConfigEntry<bool> _enableLogging;

		public ConfigFile ConfigFile => _config;

		public bool EnableHotkeys
		{
			get
			{
				return _enableHotkeys?.Value ?? true;
			}
			set
			{
				if (_enableHotkeys != null)
				{
					_enableHotkeys.Value = value;
				}
			}
		}

		public bool ShowDebugInfo
		{
			get
			{
				return _showDebugInfo?.Value ?? false;
			}
			set
			{
				if (_showDebugInfo != null)
				{
					_showDebugInfo.Value = value;
				}
			}
		}

		public bool EnableLogging
		{
			get
			{
				return _enableLogging?.Value ?? true;
			}
			set
			{
				if (_enableLogging != null)
				{
					_enableLogging.Value = value;
				}
			}
		}

		public float MenuWidth { get; private set; }

		public float MenuHeight { get; private set; }

		public int FontSize { get; private set; }

		public PluginConfig(ConfigFile config)
		{
			_config = config;
			LoadConfig();
		}

		private void LoadConfig()
		{
			LoadGeneralSettings();
			LoadDebugMenuSettings();
		}

		private void LoadGeneralSettings()
		{
			_enableHotkeys = _config.Bind<bool>("General", "EnableHotkeys", true, "Enable keyboard hotkeys for quick actions");
			_showDebugInfo = _config.Bind<bool>("General", "ShowDebugInfo", false, "Show debug information on screen");
			_enableLogging = _config.Bind<bool>("General", "EnableLogging", true, "Enable logging to BepInEx console");
		}

		private void LoadDebugMenuSettings()
		{
			MenuWidth = _config.Bind<float>("DebugMenu", "MenuWidth", 400f, "Width of the debug menu window").Value;
			MenuHeight = _config.Bind<float>("DebugMenu", "MenuHeight", 600f, "Height of the debug menu window").Value;
			FontSize = _config.Bind<int>("DebugMenu", "FontSize", 14, "Font size for debug menu text").Value;
		}
	}
	public static class PluginInfo
	{
		public const string GUID = "ru.catalyst.silksongmanager";

		public const string NAME = "Silksong Manager";

		public const string VERSION = "1.0.0.2";

		public const string AUTHOR = "Catalyst";

		public const string EMAIL = "[email protected]";

		public const string TELEGRAM = "@Catalyst_Kyokai";
	}
}
namespace SilksongManager.World
{
	public static class WorldActions
	{
		private static Vector3 _savedPosition = Vector3.zero;

		private static string _savedScene = "";

		private static List<string> _visitedScenes = new List<string>();

		public static void SavePosition()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			HeroController hero = Plugin.Hero;
			if (!((Object)(object)hero == (Object)null))
			{
				_savedPosition = ((Component)hero).transform.position;
				_savedScene = Plugin.GM?.sceneName ?? "";
				Plugin.Log.LogInfo((object)$"Saved position: {_savedPosition} in scene {_savedScene}");
			}
		}

		public static void LoadPosition()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			if (_savedPosition == Vector3.zero)
			{
				Plugin.Log.LogWarning((object)"No position saved.");
				return;
			}
			string text = Plugin.GM?.sceneName ?? "";
			if (text != _savedScene)
			{
				Plugin.Log.LogWarning((object)("Cannot teleport: different scene. Saved: " + _savedScene + ", Current: " + text));
			}
			else
			{
				PlayerActions.TeleportTo(_savedPosition);
			}
		}

		public static string GetCurrentSceneName()
		{
			return Plugin.GM?.sceneName ?? "Unknown";
		}

		public static void TransitionToScene(string sceneName, string gateName = "")
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			GameManager gM = Plugin.GM;
			if ((Object)(object)gM == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Cannot transition: GameManager not available.");
				return;
			}
			SceneLoadInfo val = new SceneLoadInfo
			{
				SceneName = sceneName,
				EntryGateName = gateName,
				PreventCameraFadeOut = false,
				WaitForSceneTransitionCameraFade = true,
				EntryDelay = 0f,
				Visualization = (SceneLoadVisualizations)0
			};
			gM.BeginSceneTransition(val);
			Plugin.Log.LogInfo((object)("Transitioning to scene: " + sceneName));
		}

		public static string ReloadCurrentScene()
		{
			string currentSceneName = GetCurrentSceneName();
			if (currentSceneName == "Unknown")
			{
				return null;
			}
			TransitionToScene(currentSceneName);
			return currentSceneName;
		}

		public static void Respawn()
		{
			if ((Object)(object)Plugin.GM == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Cannot respawn: GameManager not available.");
			}
			else if ((Object)(object)Plugin.Hero != (Object)null)
			{
				((MonoBehaviour)Plugin.Hero).StartCoroutine(Plugin.Hero.HazardRespawn());
				Plugin.Log.LogInfo((object)"Player respawned.");
			}
		}

		public static WorldInfo GetWorldInfo()
		{
			GameManager gM = Plugin.GM;
			if ((Object)(object)gM == (Object)null)
			{
				return default(WorldInfo);
			}
			return new WorldInfo
			{
				CurrentScene = gM.sceneName,
				EntryGate = gM.GetEntryGateName(),
				IsGamePaused = gM.IsGamePaused()
			};
		}

		public static void PauseGame()
		{
			Time.timeScale = 0f;
			Plugin.Log.LogInfo((object)"Game paused.");
		}

		public static void ResumeGame()
		{
			SpeedControlManager.ApplyGlobalSpeed();
			Plugin.Log.LogInfo((object)"Game resumed.");
		}

		[Obsolete("Use SpeedControl.SpeedControlManager.SetGlobalSpeed instead")]
		public static void SetGameSpeed(float speed)
		{
			SpeedControlManager.SetGlobalSpeed(speed);
		}
	}
	public struct WorldInfo
	{
		public string CurrentScene;

		public string EntryGate;

		public bool IsGamePaused;
	}
}
namespace SilksongManager.UI
{
	public class NotificationManager : MonoBehaviour
	{
		private class Notification
		{
			public string Title;

			public string Message;

			public float Duration;

			public float TimeRemaining;

			public float Alpha;

			public NotificationState State;
		}

		private enum NotificationState
		{
			FadingIn,
			Visible,
			FadingOut
		}

		private static NotificationManager _instance;

		private readonly List<Notification> _notifications = new List<Notification>();

		private const float FADE_DURATION = 0.25f;

		private const float DEFAULT_DURATION = 2f;

		private const float NOTIFICATION_HEIGHT = 50f;

		private const float NOTIFICATION_WIDTH = 280f;

		private const float PADDING = 15f;

		private const float SPACING = 8f;

		private const int MAX_NOTIFICATIONS = 5;

		private GUIStyle _titleStyle;

		private GUIStyle _messageStyle;

		private GUIStyle _boxStyle;

		private Texture2D _backgroundTexture;

		private bool _stylesInitialized;

		public static NotificationManager Instance => _instance;

		private void Awake()
		{
			if ((Object)(object)_instance != (Object)null && (Object)(object)_instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)this);
			}
			else
			{
				_instance = this;
			}
		}

		private void Update()
		{
			UpdateNotifications();
		}

		private void OnGUI()
		{
			if (_notifications.Count != 0)
			{
				InitializeStyles();
				DrawNotifications();
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_backgroundTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_backgroundTexture);
			}
		}

		public static void Show(string title, string message = null, float duration = 2f)
		{
			if ((Object)(object)_instance == (Object)null)
			{
				Plugin.Log.LogWarning((object)"NotificationManager not initialized");
			}
			else
			{
				_instance.AddNotification(title, message, duration);
			}
		}

		private void AddNotification(string title, string message, float duration)
		{
			while (_notifications.Count >= 5)
			{
				_notifications.RemoveAt(0);
			}
			Notification item = new Notification
			{
				Title = title,
				Message = message,
				Duration = duration,
				TimeRemaining = duration,
				Alpha = 0f,
				State = NotificationState.FadingIn
			};
			_notifications.Add(item);
			Plugin.Log.LogInfo((object)("[Notification] " + title + ": " + message));
		}

		private void UpdateNotifications()
		{
			for (int num = _notifications.Count - 1; num >= 0; num--)
			{
				Notification notification = _notifications[num];
				switch (notification.State)
				{
				case NotificationState.FadingIn:
					notification.Alpha += Time.unscaledDeltaTime / 0.25f;
					if (notification.Alpha >= 1f)
					{
						notification.Alpha = 1f;
						notification.State = NotificationState.Visible;
					}
					break;
				case NotificationState.Visible:
					notification.TimeRemaining -= Time.unscaledDeltaTime;
					if (notification.TimeRemaining <= 0f)
					{
						notification.State = NotificationState.FadingOut;
					}
					break;
				case NotificationState.FadingOut:
					notification.Alpha -= Time.unscaledDeltaTime / 0.25f;
					if (notification.Alpha <= 0f)
					{
						_notifications.RemoveAt(num);
					}
					break;
				}
			}
		}

		private void InitializeStyles()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_008d: Expected O, but got Unknown
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00d7: Expected O, but got Unknown
			//IL_00e2: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			if (!_stylesInitialized)
			{
				_backgroundTexture = new Texture2D(1, 1);
				_backgroundTexture.SetPixel(0, 0, new Color(0.1f, 0.1f, 0.12f, 0.95f));
				_backgroundTexture.Apply();
				GUIStyle val = new GUIStyle(GUI.skin.box);
				val.normal.background = _backgroundTexture;
				val.border = new RectOffset(4, 4, 4, 4);
				val.padding = new RectOffset(12, 12, 8, 8);
				_boxStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1
				};
				val2.normal.textColor = new Color(0.95f, 0.75f, 0.3f);
				val2.alignment = (TextAnchor)3;
				_titleStyle = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					fontSize = 12
				};
				val3.normal.textColor = new Color(0.85f, 0.85f, 0.9f);
				val3.alignment = (TextAnchor)3;
				_messageStyle = val3;
				_stylesInitialized = true;
			}
		}

		private void DrawNotifications()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			float num = 15f;
			Rect val = default(Rect);
			for (int num2 = _notifications.Count - 1; num2 >= 0; num2--)
			{
				Notification notification = _notifications[num2];
				float num3 = (string.IsNullOrEmpty(notification.Message) ? 35f : 50f);
				((Rect)(ref val))..ctor((float)Screen.width - 280f - 15f, num, 280f, num3);
				Color color = GUI.color;
				GUI.color = new Color(1f, 1f, 1f, notification.Alpha);
				GUI.Box(val, GUIContent.none, _boxStyle);
				GUI.Label(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 6f, ((Rect)(ref val)).width - 24f, 20f), notification.Title, _titleStyle);
				if (!string.IsNullOrEmpty(notification.Message))
				{
					GUI.Label(new Rect(((Rect)(ref val)).x + 12f, ((Rect)(ref val)).y + 26f, ((Rect)(ref val)).width - 24f, 18f), notification.Message, _messageStyle);
				}
				GUI.color = color;
				num += num3 + 8f;
			}
		}
	}
}
namespace SilksongManager.Tools
{
	public static class ToolActions
	{
		public static void UnlockAllTools()
		{
			ToolItemManager.UnlockAllTools();
			Plugin.Log.LogInfo((object)"Unlocked all tools.");
		}

		public static void UnlockAllCrests()
		{
			ToolItemManager.UnlockAllCrests();
			Plugin.Log.LogInfo((object)"Unlocked all crests.");
		}

		public static List<ToolInfo> GetAllTools()
		{
			List<ToolInfo> list = new List<ToolInfo>();
			foreach (ToolItem allTool in ToolItemManager.GetAllTools())
			{
				if ((Object)(object)allTool != (Object)null)
				{
					list.Add(new ToolInfo
					{
						Name = allTool.name,
						IsUnlocked = allTool.IsUnlocked
					});
				}
			}
			return list;
		}

		public static List<ToolInfo> GetUnlockedTools()
		{
			List<ToolInfo> list = new List<ToolInfo>();
			foreach (ToolItem unlockedTool in ToolItemManager.GetUnlockedTools())
			{
				if ((Object)(object)unlockedTool != (Object)null)
				{
					list.Add(new ToolInfo
					{
						Name = unlockedTool.name,
						IsUnlocked = true
					});
				}
			}
			return list;
		}

		public static List<CrestInfo> GetAllCrests()
		{
			List<CrestInfo> list = new List<CrestInfo>();
			foreach (ToolCrest allCrest in ToolItemManager.GetAllCrests())
			{
				if ((Object)(object)allCrest != (Object)null)
				{
					list.Add(new CrestInfo
					{
						Name = allCrest.name,
						IsUnlocked = allCrest.IsUnlocked
					});
				}
			}
			return list;
		}

		public static void ReplenishAllTools()
		{
			ToolItemManager.TryReplenishTools(true, (ReplenishMethod)0);
			Plugin.Log.LogInfo((object)"Replenished all tools.");
		}

		public static bool UnlockTool(string toolName)
		{
			ToolItem toolByName = ToolItemManager.GetToolByName(toolName);
			if ((Object)(object)toolByName == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Tool not found: " + toolName));
				return false;
			}
			((SavedItem)toolByName).Get(true);
			Plugin.Log.LogInfo((object)("Unlocked tool: " + toolName));
			return true;
		}

		public static bool LockTool(string toolName)
		{
			ToolItem toolByName = ToolItemManager.GetToolByName(toolName);
			if ((Object)(object)toolByName == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Tool not found: " + toolName));
				return false;
			}
			toolByName.Lock();
			Plugin.Log.LogInfo((object)("Locked tool: " + toolName));
			return true;
		}

		public static void LockAllTools()
		{
			foreach (ToolItem allTool in ToolItemManager.GetAllTools())
			{
				if ((Object)(object)allTool != (Object)null && allTool.IsUnlocked)
				{
					allTool.Lock();
				}
			}
			Plugin.Log.LogInfo((object)"Locked all tools.");
		}

		public static List<ToolInfo> GetNonCrestTools()
		{
			List<ToolInfo> list = new List<ToolInfo>();
			foreach (ToolItem allTool in ToolItemManager.GetAllTools())
			{
				if (!((Object)(object)allTool == (Object)null))
				{
					list.Add(new ToolInfo
					{
						Name = allTool.name,
						IsUnlocked = allTool.IsUnlocked
					});
				}
			}
			return list;
		}
	}
	public struct ToolInfo
	{
		public string Name;

		public bool IsUnlocked;
	}
	public struct CrestInfo
	{
		public string Name;

		public bool IsUnlocked;
	}
}
namespace SilksongManager.SpeedControl
{
	public class EnemySpeedScaler : MonoBehaviour
	{
		private Rigidbody2D _rb;

		private HealthManager _hm;

		private const float WALK_SPEED_MAX = 25f;

		private const float MIN_SPEED = 0.5f;

		private void Awake()
		{
			_rb = ((Component)this).GetComponent<Rigidbody2D>();
			_hm = ((Component)this).GetComponent<HealthManager>();
			if ((Object)(object)_hm == (Object)null)
			{
				_hm = ((Component)this).GetComponentInParent<HealthManager>();
			}
		}

		private void FixedUpdate()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rb == (Object)null || (Object)(object)_hm == (Object)null || !SpeedControlConfig.IsEnabled)
			{
				return;
			}
			float effectiveEnemyMovement = SpeedControlConfig.EffectiveEnemyMovement;
			if (!Mathf.Approximately(effectiveEnemyMovement, 1f))
			{
				Vector2 linearVelocity = _rb.linearVelocity;
				float magnitude = ((Vector2)(ref linearVelocity)).magnitude;
				if (!(magnitude < 0.5f) && !(magnitude > 25f))
				{
					Vector2 normalized = ((Vector2)(ref linearVelocity)).normalized;
					float num = magnitude * effectiveEnemyMovement;
					num = Mathf.Min(num, 25f);
					_rb.linearVelocity = normalized * num;
				}
			}
		}
	}
	public class ProjectileSpeedScaler : MonoBehaviour
	{
		private Rigidbody2D _rb;

		private bool _hasScaled;

		private float _appliedMult = 1f;

		private void Awake()
		{
			_rb = ((Component)this).GetComponent<Rigidbody2D>();
		}

		private void OnEnable()
		{
			_hasScaled = false;
			_appliedMult = 1f;
			if ((Object)(object)_rb == (Object)null)
			{
				_rb = ((Component)this).GetComponent<Rigidbody2D>();
			}
		}

		private void Start()
		{
			TryScale();
		}

		private void FixedUpdate()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasScaled)
			{
				TryScale();
				return;
			}
			float effectiveEnemyAttack = SpeedControlConfig.EffectiveEnemyAttack;
			if (Mathf.Abs(effectiveEnemyAttack - _appliedMult) > 0.01f && (Object)(object)_rb != (Object)null)
			{
				Vector2 linearVelocity = _rb.linearVelocity;
				if (((Vector2)(ref linearVelocity)).sqrMagnitude > 0.1f)
				{
					_rb.linearVelocity = _rb.linearVelocity / _appliedMult * effectiveEnemyAttack;
					_appliedMult = effectiveEnemyAttack;
				}
			}
		}

		private void TryScale()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_rb == (Object)null || !SpeedControlConfig.IsEnabled)
			{
				return;
			}
			float effectiveEnemyAttack = SpeedControlConfig.EffectiveEnemyAttack;
			if (Mathf.Approximately(effectiveEnemyAttack, 1f))
			{
				_hasScaled = true;
				_appliedMult = 1f;
				return;
			}
			Vector2 linearVelocity = _rb.linearVelocity;
			if (!(((Vector2)(ref linearVelocity)).sqrMagnitude < 0.1f))
			{
				_rb.linearVelocity = linearVelocity * effectiveEnemyAttack;
				_hasScaled = true;
				_appliedMult = effectiveEnemyAttack;
			}
		}
	}
	public static class SpeedControlConfig
	{
		public static float GlobalSpeed { get; set; } = 1f;

		public static float PlayerMovementSpeed { get; set; } = 1f;

		public static float PlayerAttackSpeed { get; set; } = 1f;

		public static float PlayerAllSpeed { get; set; } = 1f;

		public static float EffectivePlayerMovement => PlayerMovementSpeed * PlayerAllSpeed;

		public static float EffectivePlayerAttack => PlayerAttackSpeed * PlayerAllSpeed;

		public static float EnemyMovementSpeed { get; set; } = 1f;

		public static float EnemyAttackSpeed { get; set; } = 1f;

		public static float EnemyAllSpeed { get; set; } = 1f;

		public static float EffectiveEnemyMovement => EnemyMovementSpeed * EnemyAllSpeed;

		public static float EffectiveEnemyAttack => EnemyAttackSpeed * EnemyAllSpeed;

		public static bool IsEnabled { get; set; } = true;

		internal static float OriginalRunSpeed { get; set; } = 0f;

		internal static float OriginalWalkSpeed { get; set; } = 0f;

		internal static bool OriginalsCaptured { get; set; } = false;

		public static void ResetAll()
		{
			GlobalSpeed = 1f;
			PlayerMovementSpeed = 1f;
			PlayerAttackSpeed = 1f;
			PlayerAllSpeed = 1f;
			EnemyMovementSpeed = 1f;
			EnemyAttackSpeed = 1f;
			EnemyAllSpeed = 1f;
		}

		public static bool IsAnyModified()
		{
			if (GlobalSpeed == 1f && PlayerMovementSpeed == 1f && PlayerAttackSpeed == 1f && PlayerAllSpeed == 1f && EnemyMovementSpeed == 1f && EnemyAttackSpeed == 1f)
			{
				return EnemyAllSpeed != 1f;
			}
			return true;
		}
	}
	public static class SpeedControlManager
	{
		private static bool _initialized;

		private static HeroController _cachedHero;

		public static void Initialize()
		{
			if (!_initialized)
			{
				SpeedControlPatches.Apply();
				SceneManager.sceneLoaded += OnSceneLoaded;
				_initialized = true;
				Plugin.Log.LogInfo((object)"SpeedControl system initialized");
			}
		}

		public static void Shutdown()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			SpeedControlPatches.Remove();
			SpeedControlConfig.ResetAll();
			_initialized = false;
		}

		public static void SetGlobalSpeed(float speed)
		{
			SpeedControlConfig.GlobalSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyGlobalSpeed();
			Plugin.Log.LogInfo((object)$"Global speed set to {SpeedControlConfig.GlobalSpeed:F2}x");
		}

		public static void ApplyGlobalSpeed()
		{
			if (SpeedControlConfig.IsEnabled)
			{
				GameManager gM = Plugin.GM;
				if (!((Object)(object)gM != (Object)null) || !gM.IsGamePaused())
				{
					Time.timeScale = SpeedControlConfig.GlobalSpeed;
				}
			}
		}

		public static void SetPlayerMovementSpeed(float speed)
		{
			SpeedControlConfig.PlayerMovementSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyPlayerSpeed();
			Plugin.Log.LogInfo((object)$"Player movement speed set to {speed:F2}x");
		}

		public static void SetPlayerAttackSpeed(float speed)
		{
			SpeedControlConfig.PlayerAttackSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyPlayerAttackSpeed();
			Plugin.Log.LogInfo((object)$"Player attack speed set to {speed:F2}x");
		}

		public static void SetPlayerAllSpeed(float speed)
		{
			SpeedControlConfig.PlayerAllSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyPlayerSpeed();
			ApplyPlayerAttackSpeed();
			Plugin.Log.LogInfo((object)$"Player all speed set to {speed:F2}x");
		}

		public static void ApplyPlayerSpeed()
		{
			if (!SpeedControlConfig.IsEnabled)
			{
				return;
			}
			HeroController hero = Plugin.Hero;
			if (!((Object)(object)hero == (Object)null))
			{
				if (!SpeedControlConfig.OriginalsCaptured || SpeedControlConfig.OriginalRunSpeed <= 0f)
				{
					SpeedControlConfig.OriginalRunSpeed = 8.3f;
					SpeedControlConfig.OriginalWalkSpeed = 3.3f;
					SpeedControlConfig.OriginalsCaptured = true;
					Plugin.Log.LogInfo((object)$"Speed originals set: Run={SpeedControlConfig.OriginalRunSpeed}, Walk={SpeedControlConfig.OriginalWalkSpeed}");
				}
				float effectivePlayerMovement = SpeedControlConfig.EffectivePlayerMovement;
				hero.RUN_SPEED = SpeedControlConfig.OriginalRunSpeed * effectivePlayerMovement;
				hero.WALK_SPEED = SpeedControlConfig.OriginalWalkSpeed * effectivePlayerMovement;
			}
		}

		public static void ApplyPlayerAttackSpeed()
		{
		}

		public static void SetEnemyMovementSpeed(float speed)
		{
			SpeedControlConfig.EnemyMovementSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyEnemySpeed();
			Plugin.Log.LogInfo((object)$"Enemy movement speed set to {speed:F2}x");
		}

		public static void SetEnemyAttackSpeed(float speed)
		{
			SpeedControlConfig.EnemyAttackSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyEnemyAnimatorSpeed();
			Plugin.Log.LogInfo((object)$"Enemy attack speed set to {speed:F2}x");
		}

		public static void SetEnemyAllSpeed(float speed)
		{
			SpeedControlConfig.EnemyAllSpeed = Mathf.Clamp(speed, 0.1f, 10f);
			ApplyEnemySpeed();
			ApplyEnemyAnimatorSpeed();
			Plugin.Log.LogInfo((object)$"Enemy all speed set to {speed:F2}x");
		}

		public static void ApplyEnemySpeed()
		{
		}

		public static void ApplyEnemyAnimatorSpeed()
		{
			if (!SpeedControlConfig.IsEnabled)
			{
				return;
			}
			float effectiveEnemyAttack = SpeedControlConfig.EffectiveEnemyAttack;
			foreach (HealthManager item in HealthManager.EnumerateActiveEnemies())
			{
				if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null)
				{
					continue;
				}
				Animator[] componentsInChildren = ((Component)item).GetComponentsInChildren<Animator>();
				foreach (Animator val in componentsInChildren)
				{
					if ((Object)(object)val != (Object)null)
					{
						val.speed = effectiveEnemyAttack;
					}
				}
			}
		}

		public static void ResetAll()
		{
			SpeedControlConfig.ResetAll();
			HeroController hero = Plugin.Hero;
			if ((Object)(object)hero != (Object)null && SpeedControlConfig.OriginalsCaptured)
			{
				hero.RUN_SPEED = SpeedControlConfig.OriginalRunSpeed;
				hero.WALK_SPEED = SpeedControlConfig.OriginalWalkSpeed;
			}
			Time.timeScale = 1f;
			SpeedControlPatches.ResetWalkerSpeeds();
			Plugin.Log.LogInfo((object)"All speeds reset to 1.0x");
		}

		public static void ApplyAllSpeeds()
		{
			if (SpeedControlConfig.IsEnabled)
			{
				ApplyGlobalSpeed();
				ApplyPlayerSpeed();
				ApplyEnemyAnimatorSpeed();
			}
		}

		private static bool IsHeroOrEnemy(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			HeroController hero = Plugin.Hero;
			if ((Object)(object)hero != (Object)null && ((Object)(object)go == (Object)(object)((Component)hero).gameObject || go.transform.IsChildOf(((Component)hero).transform)))
			{
				return true;
			}
			if ((Object)(object)go.GetComponentInParent<HealthManager>() != (Object)null)
			{
				return true;
			}
			return false;
		}

		private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			if ((Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(ApplySpeedsDelayed());
			}
		}

		private static IEnumerator ApplySpeedsDelayed()
		{
			yield return (object)new WaitForSeconds(0.5f);
			ApplyAllSpeeds();
		}

		public static void Update()
		{
			if (SpeedControlConfig.IsEnabled && SpeedControlConfig.IsAnyModified())
			{
				Mathf.Approximately(SpeedControlConfig.EffectiveEnemyMovement, 1f);
			}
		}
	}
	public static class SpeedControlPatches
	{
		private static Harmony _harmony;

		private static Type _tk2dAnimatorType;

		private static Type _tk2dClipType;

		private static PropertyInfo _clipFpsProperty;

		private static PropertyInfo _currentClipProperty;

		private static FieldInfo _clipNameField;

		private static bool _reflectionInitialized = false;

		private static HashSet<int> _enemiesWithScaler = new HashSet<int>();

		private static readonly HashSet<string> _movementAnimNames = new HashSet<string>
		{
			"Walk", "Run", "Fly", "Idle", "Turn", "Move", "walk", "run", "fly", "idle",
			"turn", "move", "Walking", "Running", "Flying", "Turning", "Moving", "walking", "running", "flying",
			"turning", "moving", "Crawl", "crawl", "Crawling", "crawling"
		};

		private static int _tk2dCallCount = 0;

		private static HashSet<int> _spawnedWithScaler = new HashSet<int>();

		public static void Apply()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			try
			{
				InitializeReflection();
				_harmony = new Harmony("com.catalyst.silksongmanager.speedcontrol");
				int count = 0;
				TryPatch(typeof(GameManager), "UnpauseGame", "GameManager_UnpauseGame_Postfix", ref count);
				TryPatch(typeof(TimeManager), "UpdateTimeScale", "TimeManager_UpdateTimeScale_Postfix", ref count);
				TryPatch(typeof(HeroController), "Start", "HeroController_Start_Postfix", ref count);
				TryPatch(typeof(HeroController), "TakeDamage", "HeroController_TakeDamage_Postfix", ref count);
				TryPatch(typeof(HeroController), "Respawn", "HeroController_Respawn_Postfix", ref count);
				TryPatch(typeof(NailSlash), "PlaySlash", "NailSlash_PlaySlash_Postfix", ref count);
				TryPatch(typeof(Downspike), "StartSlash", "Downspike_StartSlash_Postfix", ref count);
				PatchAttackCooldowns(ref count);
				PatchObjectPoolSpawn(ref count);
				TryPatch(typeof(HealthManager), "OnEnable", "HealthManager_OnEnable_Postfix", ref count);
				PatchTk2dAnimator(ref count);
				Plugin.Log.LogInfo((object)$"SpeedControlPatches: {count} patches applied");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpeedControlPatches failed: " + ex.Message + "\n" + ex.StackTrace));
			}
		}

		private static void PatchTk2dAnimator(ref int count)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Expected O, but got Unknown
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			if (_tk2dAnimatorType == null)
			{
				return;
			}
			try
			{
				MethodInfo methodInfo = AccessTools.Method(_tk2dAnimatorType, "Play", Type.EmptyTypes, (Type[])null);
				if (methodInfo != null)
				{
					MethodInfo method = typeof(SpeedControlPatches).GetMethod("Tk2d_PlayNoArgs_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched tk2d.Play()");
				}
				MethodInfo methodInfo2 = AccessTools.Method(_tk2dAnimatorType, "Play", new Type[1] { typeof(string) }, (Type[])null);
				if (methodInfo2 != null)
				{
					MethodInfo method2 = typeof(SpeedControlPatches).GetMethod("Tk2d_Play_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched tk2d.Play(string)");
				}
				if (_tk2dClipType != null)
				{
					MethodInfo methodInfo3 = AccessTools.Method(_tk2dAnimatorType, "Play", new Type[1] { _tk2dClipType }, (Type[])null);
					if (methodInfo3 != null)
					{
						MethodInfo method3 = typeof(SpeedControlPatches).GetMethod("Tk2d_PlayClip_Postfix", BindingFlags.Static | BindingFlags.Public);
						_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						count++;
						Plugin.Log.LogInfo((object)"SpeedControl: Patched tk2d.Play(clip)");
					}
					MethodInfo methodInfo4 = AccessTools.Method(_tk2dAnimatorType, "Play", new Type[3]
					{
						_tk2dClipType,
						typeof(float),
						typeof(float)
					}, (Type[])null);
					if (methodInfo4 != null)
					{
						MethodInfo method4 = typeof(SpeedControlPatches).GetMethod("Tk2d_PlayClipFps_Postfix", BindingFlags.Static | BindingFlags.Public);
						_harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(method4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						count++;
						Plugin.Log.LogInfo((object)"SpeedControl: Patched tk2d.Play(clip,float,float)");
					}
				}
				MethodInfo methodInfo5 = AccessTools.Method(_tk2dAnimatorType, "PlayFromFrame", new Type[2]
				{
					typeof(string),
					typeof(int)
				}, (Type[])null);
				if (methodInfo5 != null)
				{
					MethodInfo method5 = typeof(SpeedControlPatches).GetMethod("Tk2d_PlayFromFrame_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(method5), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched tk2d.PlayFromFrame");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpeedControl: tk2d patch failed: " + ex.Message));
			}
		}

		private static void PatchObjectPoolSpawn(ref int count)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(ObjectPool), "Spawn", new Type[5]
				{
					typeof(GameObject),
					typeof(Transform),
					typeof(Vector3),
					typeof(Quaternion),
					typeof(bool)
				}, (Type[])null);
				if (methodInfo != null)
				{
					MethodInfo method = typeof(SpeedControlPatches).GetMethod("ObjectPool_Spawn_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched ObjectPool.Spawn");
				}
				else
				{
					Plugin.Log.LogWarning((object)"SpeedControl: ObjectPool.Spawn method not found");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpeedControl: ObjectPool.Spawn patch failed: " + ex.Message));
			}
		}

		private static void PatchAttackCooldowns(ref int count)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackCooldownTime");
				if (methodInfo != null)
				{
					MethodInfo method = typeof(SpeedControlPatches).GetMethod("AttackCooldownTime_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched AttackCooldownTime");
				}
				MethodInfo methodInfo2 = AccessTools.PropertyGetter(typeof(HeroControllerConfig), "QuickAttackCooldownTime");
				if (methodInfo2 != null)
				{
					MethodInfo method2 = typeof(SpeedControlPatches).GetMethod("AttackCooldownTime_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched QuickAttackCooldownTime");
				}
				MethodInfo methodInfo3 = AccessTools.PropertyGetter(typeof(HeroControllerConfig), "AttackRecoveryTime");
				if (methodInfo3 != null)
				{
					MethodInfo method3 = typeof(SpeedControlPatches).GetMethod("AttackCooldownTime_Postfix", BindingFlags.Static | BindingFlags.Public);
					_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					count++;
					Plugin.Log.LogInfo((object)"SpeedControl: Patched AttackRecoveryTime");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpeedControl: Attack cooldown patches failed: " + ex.Message));
			}
		}

		private static void TryPatch(Type targetType, string methodName, string patchName, ref int count)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(targetType, methodName, (Type[])null, (Type[])null);
				if (!(methodInfo == null))
				{
					MethodInfo method = typeof(SpeedControlPatches).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public);
					if (!(method == null))
					{
						_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						count++;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("SpeedControl: " + targetType.Name + "." + methodName + " failed: " + ex.Message));
			}
		}

		private static void InitializeReflection()
		{
			if (_reflectionInitialized)
			{
				return;
			}
			try
			{
				Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
				foreach (Assembly assembly in assemblies)
				{
					_tk2dAnimatorType = assembly.GetType("tk2dSpriteAnimator");
					if (!(_tk2dAnimatorType != null))
					{
						continue;
					}
					_tk2dClipType = assembly.GetType("tk2dSpriteAnimationClip");
					Plugin.Log.LogInfo((object)("SpeedControl: Found tk2d type in " + assembly.GetName().Name));
					MethodInfo[] methods = _tk2dAnimatorType.GetMethods();
					foreach (MethodInfo methodInfo in methods)
					{
						if (methodInfo.Name == "Play")
						{
							ParameterInfo[] parameters = methodInfo.GetParameters();
							string text = string.Join(", ", Array.ConvertAll(parameters, (ParameterInfo p) => p.ParameterType.Name));
							Plugin.Log.LogInfo((object)("SpeedControl: Found Play(" + text + ")"));
						}
					}
					break;
				}
				if (_tk2dAnimatorType != null)
				{
					_clipFpsProperty = _tk2dAnimatorType.GetProperty("ClipFps");
					_currentClipProperty = _tk2dAnimatorType.GetProperty("CurrentClip");
				}
				if (_tk2dClipType != null)
				{
					_clipNameField = _tk2dClipType.GetField("name");
				}
			}
			catch
			{
			}
			_reflectionInitialized = true;
		}

		public static void Remove()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		public static void Tk2d_PlayNoArgs_Postfix(object __instance)
		{
			ApplyAnimationSpeedToCurrentClip(__instance);
		}

		public static void Tk2d_Play_Postfix(object __instance, string name)
		{
			_tk2dCallCount++;
			if (_tk2dCallCount <= 10)
			{
				Component val = (Component)((__instance is Component) ? __instance : null);
				ManualLogSource log = Plugin.Log;
				object arg = _tk2dCallCount;
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = val.gameObject;
					obj = ((gameObject != null) ? ((Object)gameObject).name : null);
				}
				if (obj == null)
				{
					obj = "null";
				}
				log.LogInfo((object)$"SpeedControl: tk2d.Play called #{arg}: '{name}' on {obj}");
			}
			ApplyAnimationSpeed(__instance, name);
		}

		public static void Tk2d_PlayClip_Postfix(object __instance, object clip)
		{
			string clipName = GetClipName(clip);
			_tk2dCallCount++;
			if (_tk2dCallCount <= 10)
			{
				Component val = (Component)((__instance is Component) ? __instance : null);
				ManualLogSource log = Plugin.Log;
				object arg = _tk2dCallCount;
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = val.gameObject;
					obj = ((gameObject != null) ? ((Object)gameObject).name : null);
				}
				if (obj == null)
				{
					obj = "null";
				}
				log.LogInfo((object)$"SpeedControl: tk2d.Play(clip) called #{arg}: '{clipName}' on {obj}");
			}
			ApplyAnimationSpeed(__instance, clipName);
		}

		public static void Tk2d_PlayClipFps_Postfix(object __instance, object clip)
		{
			string clipName = GetClipName(clip);
			_tk2dCallCount++;
			if (_tk2dCallCount <= 10)
			{
				Component val = (Component)((__instance is Component) ? __instance : null);
				ManualLogSource log = Plugin.Log;
				object arg = _tk2dCallCount;
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = val.gameObject;
					obj = ((gameObject != null) ? ((Object)gameObject).name : null);
				}
				if (obj == null)
				{
					obj = "null";
				}
				log.LogInfo((object)$"SpeedControl: tk2d.Play(clip,fps) called #{arg}: '{clipName}' on {obj}");
			}
			ApplyAnimationSpeed(__instance, clipName);
		}

		public static void Tk2d_PlayFromFrame_Postfix(object __instance, string name)
		{
			_tk2dCallCount++;
			if (_tk2dCallCount <= 10)
			{
				Component val = (Component)((__instance is Component) ? __instance : null);
				ManualLogSource log = Plugin.Log;
				object arg = _tk2dCallCount;
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					GameObject gameObject = val.gameObject;
					obj = ((gameObject != null) ? ((Object)gameObject).name : null);
				}
				if (obj == null)
				{
					obj = "null";
				}
				log.LogInfo((object)$"SpeedControl: tk2d.PlayFromFrame called #{arg}: '{name}' on {obj}");
			}
			ApplyAnimationSpeed(__instance, name);
		}

		private static void ApplyAnimationSpeed(object animator, string animName)
		{
			if (!SpeedControlConfig.IsEnabled || _clipFpsProperty == null)
			{
				return;
			}
			try
			{
				Component val = (Component)((animator is Component) ? animator : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				GameObject gameObject = val.gameObject;
				if (IsHeroObject(gameObject) || !IsEnemyObject(gameObject))
				{
					return;
				}
				bool num = IsMovementAnimation(animName);
				float num2 = 1f;
				if (num)
				{
					num2 = SpeedControlConfig.EffectiveEnemyMovement;
				}
				else
				{
					num2 = SpeedControlConfig.EffectiveEnemyAttack;
					if (!Mathf.Approximately(num2, 1f))
					{
						Plugin.Log.LogInfo((object)$"SpeedControl: Attack anim '{animName}' on {((Object)gameObject).name}, mult={num2}");
					}
				}
				if (!Mathf.Approximately(num2, 1f))
				{
					ApplyFpsMult(animator, num2);
				}
			}
			catch
			{
			}
		}

		private static void ApplyFpsMult(object animator, float mult)
		{
			try
			{
				float num = (float)_clipFpsProperty.GetValue(animator);
				if (num > 0f)
				{
					_clipFpsProperty.SetValue(animator, num * mult);
				}
			}
			catch
			{
			}
		}

		private static bool IsMovementAnimation(string animName)
		{
			if (string.IsNullOrEmpty(animName))
			{
				return false;
			}
			foreach (string movementAnimName in _movementAnimNames)
			{
				if (animName.Contains(movementAnimName))
				{
					return true;
				}
			}
			return false;
		}

		public static void GameManager_UnpauseGame_Postfix()
		{
			if (SpeedControlConfig.IsEnabled && SpeedControlConfig.GlobalSpeed != 1f)
			{
				Time.timeScale = SpeedControlConfig.GlobalSpeed;
			}
		}

		public static void TimeManager_UpdateTimeScale_Postfix()
		{
			if (SpeedControlConfig.IsEnabled && !Mathf.Approximately(SpeedControlConfig.GlobalSpeed, 1f))
			{
				Time.timeScale *= SpeedControlConfig.GlobalSpeed;
			}
		}

		public static void HeroController_Start_Postfix(HeroController __instance)
		{
			if (!SpeedControlConfig.OriginalsCaptured)
			{
				SpeedControlConfig.OriginalRunSpeed = __instance.RUN_SPEED;
				SpeedControlConfig.OriginalWalkSpeed = __instance.WALK_SPEED;
				SpeedControlConfig.OriginalsCaptured = true;
			}
			SpeedControlManager.ApplyPlayerSpeed();
		}

		public static void HeroController_TakeDamage_Postfix(HeroController __instance)
		{
			if (SpeedControlConfig.IsEnabled)
			{
				SpeedControlManager.ApplyPlayerSpeed();
			}
		}

		public static void HeroController_Respawn_Postfix()
		{
			if (SpeedControlConfig.IsEnabled && (Object)(object)Plugin.Instance != (Object)null)
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(ApplySpeedsNextFrame());
			}
		}

		public static void HealthManager_OnEnable_Postfix(HealthManager __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			int instanceID = ((Object)((Component)__instance).gameObject).GetInstanceID();
			if (!_enemiesWithScaler.Contains(instanceID))
			{
				if ((Object)(object)((Component)__instance).GetComponent<EnemySpeedScaler>() == (Object)null)
				{
					((Component)__instance).gameObject.AddComponent<EnemySpeedScaler>();
				}
				_enemiesWithScaler.Add(instanceID);
			}
		}

		public static void NailSlash_PlaySlash_Postfix(NailSlash __instance)
		{
			if (SpeedControlConfig.IsEnabled)
			{
				float effectivePlayerAttack = SpeedControlConfig.EffectivePlayerAttack;
				if (!Mathf.Approximately(effectivePlayerAttack, 1f))
				{
					ApplyTk2dSpeedMultiplier(((Component)__instance).gameObject, effectivePlayerAttack);
				}
			}
		}

		public static void Downspike_StartSlash_Postfix(Downspike __instance)
		{
			if (SpeedControlConfig.IsEnabled)
			{
				float effectivePlayerAttack = SpeedControlConfig.EffectivePlayerAttack;
				if (!Mathf.Approximately(effectivePlayerAttack, 1f))
				{
					ApplyTk2dSpeedMultiplier(((Component)__instance).gameObject, effectivePlayerAttack);
				}
			}
		}

		public static void AttackCooldownTime_Postfix(ref float __result)
		{
			if (SpeedControlConfig.IsEnabled)
			{
				float effectivePlayerAttack = SpeedControlConfig.EffectivePlayerAttack;
				if (!Mathf.Approximately(effectivePlayerAttack, 1f))
				{
					__result /= effectivePlayerAttack;
				}
			}
		}

		public static void ObjectPool_Spawn_Postfix(GameObject __result)
		{
			if ((Object)(object)__result == (Object)null || !SpeedControlConfig.IsEnabled)
			{
				return;
			}
			int instanceID = ((Object)__result).GetInstanceID();
			if (!_spawnedWithScaler.Contains(instanceID))
			{
				_spawnedWithScaler.Add(instanceID);
				if ((Object)(object)__result.GetComponent<Rigidbody2D>() != (Object)null && !IsHeroObject(__result) && (Object)(object)__result.GetComponent<ProjectileSpeedScaler>() == (Object)null)
				{
					__result.AddComponent<ProjectileSpeedScaler>();
				}
			}
		}

		private static bool IsHeroObject(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			HeroController instance = HeroController.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (!((Object)(object)go == (Object)(object)((Component)instance).gameObject))
			{
				return go.transform.IsChildOf(((Component)instance).transform);
			}
			return true;
		}

		private static bool IsEnemyObject(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			return (Object)(object)go.GetComponentInParent<HealthManager>() != (Object)null;
		}

		private static void ApplyTk2dSpeedMultiplier(GameObject go, float mult)
		{
			if (_tk2dAnimatorType == null || _clipFpsProperty == null)
			{
				return;
			}
			try
			{
				Component component = go.GetComponent(_tk2dAnimatorType);
				if (!((Object)(object)component == (Object)null))
				{
					float num = (float)_clipFpsProperty.GetValue(component);
					_clipFpsProperty.SetValue(component, num * mult);
				}
			}
			catch
			{
			}
		}

		private static string GetClipName(object clip)
		{
			if (clip == null || _clipNameField == null)
			{
				return "";
			}
			try
			{
				return (_clipNameField.GetValue(clip) as string) ?? "";
			}
			catch
			{
				return "";
			}
		}

		private static void ApplyAnimationSpeedToCurrentClip(object animator)
		{
			if (_currentClipProperty == null)
			{
				return;
			}
			try
			{
				string clipName = GetClipName(_currentClipProperty.GetValue(animator));
				ApplyAnimationSpeed(animator, clipName);
			}
			catch
			{
			}
		}

		private static IEnumerator ApplySpeedsNextFrame()
		{
			yield return null;
			SpeedControlManager.ApplyAllSpeeds();
		}

		public static void ResetWalkerSpeeds()
		{
		}
	}
}
namespace SilksongManager.SaveState
{
	[Serializable]
	public class BattleSceneStateData
	{
		public string GameObjectPath;

		public int CurrentWave;

		public int CurrentEnemies;

		public int EnemiesToNext;

		public bool Started;

		public bool Completed;

		public FsmStateData LogicFsmState;
	}
	[Serializable]
	public class BossSceneStateData
	{
		public bool IsActive;

		public int BossLevel;

		public bool HasTransitionedIn;

		public int BossesLeft;

		public FsmStateData ControllerFsmState;
	}
	[Serializable]
	public class SpriteRendererData
	{
		public bool Enabled;

		public Color Color;

		public int SortingOrder;

		public string SortingLayerName;

		public string SpriteName;
	}
	[Serializable]
	public class AnimatorData
	{
		public bool Enabled;

		public int StateHash;

		public float NormalizedTime;

		public float Speed;
	}
	[Serializable]
	public class ColliderData
	{
		public bool Enabled;

		public bool IsTrigger;
	}
	[Serializable]
	public class TransformData
	{
		public Vector3 LocalPosition;

		public Quaternion LocalRotation;

		public Vector3 LocalScale;
	}
	[Serializable]
	public class MeshRendererData
	{
		public bool Enabled;

		public string SortingLayerName;

		public int SortingOrder;
	}
	[Serializable]
	public class SkinnedMeshRendererData
	{
		public bool Enabled;

		public string SortingLayerName;

		public int SortingOrder;
	}
	[Serializable]
	public class ObjectComponentData
	{
		public bool IsActive;

		public SpriteRendererData SpriteRenderer;

		public MeshRendererData MeshRenderer;

		public SkinnedMeshRendererData SkinnedMeshRenderer;

		public AnimatorData Animator;

		public ColliderData Collider2D;

		public TransformData Transform;
	}
	[Serializable]
	public class EnemyStateData
	{
		public string GameObjectName;

		public string GameObjectPath;

		public bool IsActive = true;

		public int HP;

		public bool IsDead;

		public bool IsInvincible;

		public int InvincibleFromDirection;

		public bool HasHit;

		public Vector3 Position;

		public Quaternion Rotation;

		public Vector3 Scale;

		public Vector2 Velocity;

		public float AngularVelocity;

		public bool IsKinematic;

		public bool IsRecoiling;

		public float RecoilTimeRemaining;

		public int RecoilDirection;

		public List<FsmStateData> FsmStates = new List<FsmStateData>();

		public ObjectComponentData MainObjectState;

		public Dictionary<string, ObjectComponentData> ChildStates = new Dictionary<string, ObjectComponentData>();

		public Dictionary<string, bool> ChildObjectStates = new Dictionary<string, bool>();
	}
	[Serializable]
	public class FsmStateData
	{
		public string FsmName;

		public string ActiveStateName;

		public Dictionary<string, bool> BoolVariables = new Dictionary<string, bool>();

		public Dictionary<string, int> IntVariables = new Dictionary<string, int>();

		public Dictionary<string, float> FloatVariables = new Dictionary<string, float>();

		public Dictionary<string, string> StringVariables = new Dictionary<string, string>();

		public Dictionary<string, Vector3> Vector3Variables = new Dictionary<string, Vector3>();
	}
	[Serializable]
	public class SaveStateData
	{
		public string SaveName;

		public string Timestamp;

		public string SceneName;

		public string PlayerDataJson;

		public string SceneDataJson;

		public Vector3 Position;

		public Vector2 Velocity;

		public bool FacingRight;

		public bool IsGrounded;

		public int Health;

		public int MaxHealth;

		public int Silk;

		public int MaxSilk;

		public int Geo;

		public List<EnemyStateData> EnemyStates;

		public BattleSceneStateData BattleSceneState;

		public BossSceneStateData BossSceneState;

		public string GetDisplayName()
		{
			if (string.IsNullOrEmpty(SaveName))
			{
				return SceneName + " - " + Timestamp;
			}
			return SaveName;
		}
	}
	public static class SaveStateManager
	{
		private static List<SaveStateData> _saveStates = new List<SaveStateData>();

		private static string _saveFilePath;

		private static SaveStateData _pendingLoadState;

		private static Harmony _harmony;

		public static event Action OnStatesChanged;

		public static void Initialize()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			_saveFilePath = Path.Combine(Paths.ConfigPath, "SilksongManager_SaveStates.json");
			LoadStatesFromDisk();
			_harmony = new Harmony("com.silksongmanager.savestate");
			_harmony.Patch((MethodBase)AccessTools.Method(typeof(GameManager), "FindEntryPoint", (Type[])null, (Type[])null), new HarmonyMethod(typeof(SaveStateManager), "FindEntryPointPatch", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		public static List<SaveStateData> GetStates()
		{
			return _saveStates;
		}

		public static SaveStateData GetLastState()
		{
			if (_saveStates.Count == 0)
			{
				return null;
			}
			return _saveStates[_saveStates.Count - 1];
		}

		public static string QuickSave()
		{
			CaptureState();
			return GetLastState()?.GetDisplayName() ?? "Unknown";
		}

		public static string LoadLastState()
		{
			SaveStateData lastState = GetLastState();
			if (lastState == null)
			{
				Plugin.Log.LogWarning((object)"No save states available to load.");
				return null;
			}
			LoadState(lastState);
			return lastState.GetDisplayName();
		}

		public static void CaptureState(string name = null)
		{
			//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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.PD == null || (Object)(object)Plugin.Hero == (Object)null)
			{
				Plugin.Log.LogError((object)"Cannot save state: PlayerData or Hero is null");
				return;
			}
			try
			{
				SaveStateData saveStateData = new SaveStateData();
				saveStateData.SaveName = name;
				saveStateData.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
				Scene activeScene = SceneManager.GetActiveScene();
				saveStateData.SceneName = ((Scene)(ref activeScene)).name;
				saveStateData.PlayerDataJson = JsonConvert.SerializeObject((object)Plugin.PD);
				ForceSavePersistentItems();
				if (SceneData.instance != null)
				{
					saveStateData.SceneDataJson = JsonConvert.SerializeObject((object)SceneData.instance);
					Plugin.Log.LogInfo((object)$"[DEBUG] Captured SceneData, JSON length: {saveStateData.SceneDataJson?.Length ?? 0}");
				}
				HeroController hero = Plugin.Hero;
				saveStateData.Position = ((Component)hero).transform.position;
				saveStateData.Velocity = ((Component)hero).GetComponent<Rigidbody2D>().linearVelocity;
				saveStateData.FacingRight = hero.cState.facingRight;
				saveStateData.IsGrounded = hero.cState.onGround;
				saveStateData.Health = Plugin.PD.health;
				saveStateData.MaxHealth = Plugin.PD.maxHealth;
				saveStateData.Silk = Plugin.PD.silk;
				saveStateData.MaxSilk = Plugin.PD.silkMax;
				saveStateData.Geo = Plugin.PD.geo;
				saveStateData.EnemyStates = CaptureEnemyStates();
				saveStateData.BattleSceneState = CaptureBattleSceneState();
				saveStateData.BossSceneState = CaptureBossSceneState();
				_saveStates.Add(saveStateData);
				SaveStatesToDisk();
				SaveStateManager.OnStatesChanged?.Invoke();
				Plugin.Log.LogInfo((object)("Captured save state: " + saveStateData.GetDisplayName()));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to capture state: " + ex.Message));
			}
		}

		public static void LoadState(SaveStateData state)
		{
			if (state != null && !((Object)(object)Plugin.Hero == (Object)null))
			{
				((MonoBehaviour)Plugin.Instance).StartCoroutine(LoadStateCoro(state));
			}
		}

		private static IEnumerator LoadStateCoro(SaveStateData state)
		{
			Plugin.Log.LogInfo((object)("Starting robust load for state: " + state.SceneName));
			_pendingLoadState = state;
			Time.timeScale = 0f;
			if ((Object)(object)Plugin.Hero != (Object)null)
			{
				((MonoBehaviour)Plugin.Hero).StopAllCoroutines();
				((MonoBehaviour)Plugin.Hero).StopAllCoroutines();
				typeof(HeroController).GetField("hazardInvulnRoutine", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(Plugin.Hero, null);
				typeof(HeroController).GetMethod("CancelDamageRecoil", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.Invoke(Plugin.Hero, null);
				Component component = ((Component)Plugin.Hero).GetComponent("InvulnerablePulse");
				if ((Object)(object)component != (Object)null)
				{
					((object)component).GetType().GetMethod("StopInvulnerablePulse")?.Invoke(component, null);
				}
			}
			EventRegister.SendEvent("INVENTORY CANCEL", (GameObject)null);
			DialogueBox.EndConversation(true, (Action)null);
			DialogueBox.HideInstant();
			DialogueYesNoBox.ForceClose();
			QuestYesNoBox.ForceClose();
			SlideSurface[] array = Object.FindObjectsOfType<SlideSurface>();
			foreach (SlideSurface obj in array)
			{
				if ((bool)(typeof(SlideSurface).GetField("isHeroAttached", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj) ?? ((object)false)))
				{
					typeof(SlideSurface).GetMethod("Detach", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(obj, new object[1] { false });
				}
			}
			string dummySceneName = "Demo Start";
			GameManager.instance.entryGateName = "dreamGate";
			GameManager.instance.startedOnThisScene = true;
			AsyncOperationHandle<SceneInstance> val = Addressables.LoadSceneAsync((object)("Scenes/" + dummySceneName), (LoadSceneMode)0, true, 100, (SceneReleaseMode)0);
			yield return val;
			yield return (object)new WaitUntil((Func<bool>)delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name == dummySceneName;
			});
			if (Plugin.PD != null && !string.IsNullOrEmpty(state.PlayerDataJson))
			{
				JsonConvert.PopulateObject(state.PlayerDataJson, (object)Plugin.PD);
			}
			if (SceneData.instance != null && !string.IsNullOrEmpty(state.SceneDataJson))
			{
				Plugin.Log.LogInfo((object)$"[DEBUG] Restoring SceneData, JSON length: {state.SceneDataJson.Length}");
				JsonConvert.PopulateObject(state.SceneDataJson, (object)SceneData.instance);
				Plugin.Log.LogInfo((object)"[DEBUG] SceneData restored");
			}
			else
			{
				Plugin.Log.LogWarning((object)$"[DEBUG] SceneData NOT restored: instance={SceneData.instance != null}, json={!string.IsNullOrEmpty(state.SceneDataJson)}");
			}
			EventRegister.SendEvent(EventRegisterEvents.HealthUpdate, (GameObject)null);
			EventRegister.SendEvent(EventRegisterEvents.UpdateBlueHealth, (GameObject)null);
			EventRegister.SendEvent(EventRegisterEvents.RegeneratedSilkChunk, (GameObject)null);
			EventRegister.SendEvent(EventRegisterEvents.SilkCursedUpdate, (GameObject)null);
			Plugin.Log.LogInfo((object)$"[DEBUG] Sent HUD refresh events: Health={state.Health}, Silk={state.Silk}");
			StaticVariableList.ClearSceneTransitions();
			Plugin.GM.BeginSceneTransition(new SceneLoadInfo
			{
				SceneName = state.SceneName,
				EntryGateName = "dreamGate",
				HeroLeaveDirection = (GatePosition)5,
				EntryDelay = 0f,
				WaitForSceneTransitionCameraFade = false,
				Visualization = (SceneLoadVisualizations)0,
				PreventCameraFadeOut = false,
				AlwaysUnloadUnusedAssets = true
			});
			yield return (object)new WaitUntil((Func<bool>)delegate
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				Scene activeScene = SceneManager.GetActiveScene();
				return ((Scene)(ref activeScene)).name == state.SceneName;
			});
			yield return (object)new WaitUntil((Func<bool>)(() => !Plugin.GM.IsInSceneTransition));
			GameManager.instance.cameraCtrl.PositionToHero(false);
			GameManager.instance.FadeSceneIn();
			Plugin.Hero.CharmUpdate();
			QuestManager.IncrementVersion();
			CollectableItemManager.IncrementVersion();
			PlayMakerFSM.BroadcastEvent("CHARM INDICATOR CHECK");
			PlayMakerFSM.BroadcastEvent("TOOL EQUIPS CHANGED");
			PlayMakerFSM.BroadcastEvent("UPDATE NAIL DAMAGE");
			FieldInfo field = typeof(CameraController).GetField("isGameplayScene", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(GameManager.instance.cameraCtrl, true);
			}
			yield return null;
			try
			{
				RestorePersistentBoolItems();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Error restoring persistent items: " + ex));
			}
			yield return (object)new WaitForSecondsRealtime(0.2f);
			try
			{
				RestoreEnemyStates(state.EnemyStates);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Error restoring enemies: " + ex2));
			}
			try
			{
				RestoreBattleSceneState(state.BattleSceneState);
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogError((object)("Error restoring battle: " + ex3));
			}
			try
			{
				RestoreBossSceneState(state.BossSceneState);
			}
			catch (Exception ex4)
			{
				Plugin.Log.LogError((object)("Error restoring boss: " + ex4));
			}
			if (state.BattleSceneState != null || state.BossSceneState != null)
			{
				PlayMakerFSM.BroadcastEvent("BATTLE START");
			}
			ApplyStateImmediate(state);
			Plugin.Log.LogInfo((object)"[DEBUG] Force Unpausing Game...");
			try
			{
				GameManager.instance.isPaused = false;
			}
			catch (Exception ex5)
			{
				Plugin.Log.LogWarning((object)("Failed to unpause GM: " + ex5.Message));
			}
			try
			{
				GameManager.instance.FadeSceneIn();
			}
			catch (Exception ex6)
			{
				Plugin.Log.LogWarning((object)("Failed to fade scene in: " + ex6.Message));
			}
			try
			{
				GameCameras.instance.ResumeCameraShake();
			}
			catch (Exception ex7)
			{
				Plugin.Log.LogWarning((object)("Failed to resume camera shake: " + ex7.Message));
			}
			try
			{
				if ((Object)(object)GameManager.instance.inputHandler != (Object)null)
				{
					GameManager.instance.inputHandler.StartAcceptingInput();
					GameManager.instance.inputHandler.AllowPause();
				}
			}
			catch (Exception ex8)
			{
				Plugin.Log.LogWarning((object)("Failed to unlock input: " + ex8.Message));
			}
			try
			{
				Type type = Assembly.GetAssembly(typeof(GameManager)).GetType("MenuButtonList");
				if (type != null)
				{
					type.GetMethod("ClearAllLastSelected", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, null);
				}
			}
			catch (Exception ex9)
			{
				Plugin.Log.LogWarning((object)("Failed to clear menus: " + ex9.Message));
			}
			try
			{
				Time.timeScale = 1f;
				Type type2 = Assembly.GetAssembly(typeof(GameManager)).GetType("TimeManager");
				if (type2 != null)
				{
					type2.GetProperty("TimeScale", BindingFlags.Static | BindingFlags.Public)?.SetValue(null, 1f);
				}
			}
			catch (Exception ex10)
			{
				Plugin.Log.LogWarning((object)("Failed to set TimeScale: " + ex10.Message));
			}
			Plugin.Log.LogInfo((object)"[DEBUG] Unpause sequence completed");
			yield return (object)new WaitForFixedUpdate();
			((Component)Plugin.Hero).transform.position = state.Position;
			Physics2D.SyncTransforms();
			yield return (object)new WaitForFixedUpdate();
			ForceEnemyRedetection();
			Vector3 savedPos = ((Component)Plugin.Hero).transform.position;
			((Component)Plugin.Hero).transform.position = new Vector3(9999f, 9999f, savedPos.z);
			Physics2D.SyncTransforms();
			yield return (object)new WaitForFixedUpdate();
			((Component)Plugin.Hero).transform.position = savedPos;
			Physics2D.SyncTransforms();
			yield return (object)new WaitForFixedUpdate();
			Plugin.Log.LogInfo((object)"[DEBUG] Forced hero position reset for Physics2D collision re-detection");
			Plugin.Log.LogInfo((object)$"[DEBUG] Before restore: health={Plugin.PD.health}, silk={Plugin.PD.silk}");
			Plugin.PD.health = state.Health;
			Plugin.PD.silk = state.Silk;
			Plugin.PD.geo = state.Geo;
			Plugin.Log.LogInfo((object)$"[DEBUG] After restore: health={Plugin.PD.health}, silk={Plugin.PD.silk}, geo={Plugin.PD.geo}");
			yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)GameCameras.instance?.hudCanvasSlideOut != (Object)null));
			yield return null;
			try
			{
				Plugin.Log.LogInfo((object)$"[DEBUG] Triggering health UI update via TakeHealth/AddHealth, health={Plugin.PD.health}");
				Plugin.Hero.TakeHealth(1);
				Plugin.Hero.AddHealth(1);
				Plugin.Log.LogInfo((object)$"[DEBUG] After TakeHealth/AddHealth, health={Plugin.PD.health}");
				Plugin.Hero.ClearEffects();
				int healthBlue = Plugin.PD.healthBlue;
				for (int num = 0; num < healthBlue; num++)
				{
					EventRegister.SendEvent("ADD BLUE HEALTH", (GameObject)null);
				}
				Plugin.Log.LogInfo((object)$"[DEBUG] Health UI refresh completed, blueHealth={healthBlue}");
				if ((Object)(object)GameCameras.instance.silkSpool != (Object)null)
				{
					GameCameras.instance.silkSpool.DrawSpool();
					Plugin.Log.LogInfo((object)"[DEBUG] Called silkSpool.DrawSpool()");
				}
				PlayMakerFSM.BroadcastEvent("CHARM INDICATOR CHECK");
				PlayMakerFSM.BroadcastEvent("TOOL EQUIPS CHANGED");
				Plugin.Log.LogInfo((object)"[DEBUG] HUD refresh completed");
			}
			catch (Exception ex11)
			{
				Plugin.Log.LogWarning((object)("HUD refresh failed: " + ex11.Message));
			}
			Time.timeScale = 1f;
			_pendingLoadState = null;
			Plugin.Log.LogInfo((object)"Load complete!");
		}

		private static void ForceEnemyRedetection()
		{
			Plugin.Log.LogInfo((object)"[DEBUG] ForceEnemyRedetection: Starting...");
			HealthManager[] array = Object.FindObjectsByType<HealthManager>((FindObjectsInactive)0, (FindObjectsSortMode)0);
			int num = 0;
			int num2 = 0;
			HealthManager[] array2 = array;
			foreach (HealthManager val in array2)
			{
				if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy)
				{
					continue;
				}
				Collider2D[] componentsInChildren = ((Component)val).GetComponentsInChildren<Collider2D>(true);
				foreach (Collider2D val2 in componentsInChildren)
				{
					string text = ((Object)((Component)val2).gameObject).name.ToLower();
					if ((text.Contains("alert") || text.Contains("wake") || text.Contains("range") || text.Contains("detect") || text.Contains("sense")) && val2.isTrigger)
					{
						bool enabled = ((Behaviour)val2).enabled;
						((Behaviour)val2).enabled = false;
						((Behaviour)val2).enabled = enabled;
						num++;
					}
				}
				Crawler component = ((Component)val).GetComponent<Crawler>();
				if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled)
				{
					try
					{
						component.StopCrawling();
						component.StartCrawling();
						num2++;
						Plugin.Log.LogInfo((object)("[DEBUG] Restarted Crawler on " + ((Object)((Component)val).gameObject).name));
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("Failed to restart Crawler on " + ((Object)((Component)val).gameObject).name + ": " + ex.Message));
					}
				}
				PlayMakerFSM[] components = ((Component)val).GetComponents<PlayMakerFSM>();
				foreach (PlayMakerFSM val3 in components)
				{
					if (val3.FsmName == "Control" && ((Behaviour)val3).enabled)
					{
						val3.SendEvent("FINISHED");
					}
				}
				DamageHero component2 = ((Component)val).GetComponent<DamageHero>();
				if ((Object)(object)component2 != (Object)null && ((Behaviour)component2).enabled)
				{
					((Behaviour)component2).enabled = false;
					((Behaviour)component2).enabled = true;
					Plugin.Log.LogInfo((object)("[DEBUG] Toggled DamageHero on " + ((Object)((Component)val).gameObject).name));
				}
				Collider2D component3 = ((Component)val).GetComponent<Collider2D>();
				if ((Object)(object)component3 != (Object)null && ((Behaviour)component3).enabled)
				{
					((Behaviour)component3).enabled = false;
					((Behaviour)component3).enabled = true;
				}
			}
			Plugin.Log.LogInfo((object)$"[DEBUG] ForceEnemyRedetection: Toggled {num} alert triggers, restarted {num2} crawlers");
		}

		public static void DeleteState(SaveStateData state)
		{
			if (_saveStates.Remove(state))
			{
				SaveStatesToDisk();
				SaveStateManager.OnStatesChanged?.Invoke();
			}
		}

		private static void ApplyStateImmediate(SaveStateData state)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)Plugin.Hero == (Object)null)
				{
					return;
				}
				HeroController hero = Plugin.Hero;
				((Component)hero).transform.position = state.Position;
				((Component)hero).GetComponent<Rigidbody2D>().linearVelocity = Vector2.zero;
				((Component)hero).GetComponent<Rigidbody2D>().bodyType = (RigidbodyType2D)0;
				hero.AffectedByGravity(true);
				((Component)hero).GetComponent<Rigidbody2D>().gravityScale = 0.79f;
				if (state.FacingRight)
				{
					hero.FaceRight();
				}
				else
				{
					hero.FaceLeft();
				}
				hero.cState.transitioning = false;
				hero.cState.dead = false;
				hero.cState.hazardDeath = false;
				hero.cState.recoiling = false;
				hero.cState.shadowDashing = false;
				hero.transitionState = (HeroTransitionState)0;
				hero.SetDamageMode((DamageMode)0);
				HeroBox.Inactive = false;
				Plugin.Log.LogInfo((object)"[DEBUG] Reset HeroBox.Inactive = false");
				hero.cState.invulnerable = false;
				hero.cState.ClearInvulnerabilitySources();
				Plugin.Log.LogInfo((object)"[DEBUG] Cleared cState invulnerability sources");
				HeroInvincibilitySource.Clear();
				Plugin.Log.LogInfo((object)$"[DEBUG] HeroInvincibilitySource.Clear(), IsActive={HeroInvincibilitySource.IsActive}");
				hero.parryInvulnTimer = 0f;
				hero.cState.downspikeInvulnerabilitySteps = 0;
				if (!CheatSystem.UserInvincible && !CheatSystem.NoclipEnabled)
				{
					Plugin.PD.isInvincible = false;
				}
				MethodInfo method = typeof(HeroController).GetMethod("FinishedEnteringScene", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (method != null)
				{
					method.Invoke(hero, new object[2] { true, false });
				}
				try
				{
					GameManager.instance.FinishedEnteringScene();
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Failed to call GM.FinishedEnteringScene: " + ex.Message));
				}
				((Renderer)((Component)hero).GetComponent<MeshRenderer>()).enabled = true;
				Collider2D component = ((Component)hero).GetComponent<Collider2D>();
				if ((Object)(object)component != (Object)null)
				{
					((Behaviour)component).enabled = true;
				}
				hero.StartAnimationControl();
				HeroAnimationController component2 = ((Component)hero).GetComponent<HeroAnimationController>();
				if (state.IsGrounded)
				{
					hero.cState.onGround = true;
					component2.PlayClip("Idle");
					object? obj = typeof(HeroController).GetField("proxyFSM", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(hero);
					object? obj2 = ((obj is PlayMakerFSM) ? obj : null);
					if (obj2 != null)
					{
						((PlayMakerFSM)obj2).SendEvent("HeroCtrl-Idle");
					}
				}
				else
				{
					hero.cState.onGround = false;
					component2.PlayClip("Fall");
				}
				hero.AcceptInput();
				Plugin.Log.LogInfo((object)"========== HERO DEBUG LOG ==========");
				Plugin.Log.LogInfo((object)$"Hero Layer: {((Component)hero).gameObject.layer} (LayerMask.LayerToName: {LayerMask.LayerToName(((Component)hero).gameObject.layer)})");
				Plugin.Log.LogInfo((object)("Hero Tag: " + ((Component)hero).gameObject.tag));
				Plugin.Log.LogInfo((object)$"Hero Active: {((Component)hero).gameObject.activeInHierarchy}");
				Plugin.Log.LogInfo((object)$"Hero Position: {((Component)hero).transform.position}");
				Plugin.Log.LogInfo((object)$"cState.transitioning: {hero.cState.transitioning}");
				Plugin.Log.LogInfo((object)$"cState.dead: {hero.cState.dead}");
				Plugin.Log.LogInfo((object)$"cState.hazardDeath: {hero.cState.hazardDeath}");
				Plugin.Log.LogInfo((object)$"cState.Invulnerable: {hero.cState.Invulnerable}");
				Plugin.Log.LogInfo((object)$"transitionState: {hero.transitionState}");
				Plugin.Log.LogInfo((object)$"damageMode: {hero.damageMode}");
				Plugin.Log.LogInfo((object)$"isInvincible (PD): {Plugin.PD?.isInvincible}");
				Collider2D[] components = ((Component)hero).GetComponents<Collider2D>();
				Plugin.Log.LogInfo((object)$"Hero Colliders ({components.Length}):");
				Collider2D[] array = components;
				foreach (Collider2D val in array)
				{
					Plugin.Log.LogInfo((object)$"  - {((object)val).GetType().Name}: enabled={((Behaviour)val).enabled}, isTrigger={val.isTrigger}");
				}
				if ((Object)(object)hero.heroBox != (Object)null)
				{
					Plugin.Log.LogInfo((object)$"HeroBox: active={((Component)hero.heroBox).gameObject.activeInHierarchy}");
					Collider2D component3 = ((Component)hero.heroBox).GetComponent<Collider2D>();
					if ((Object)(object)component3 != (Object)null)
					{
						Plugin.Log.LogInfo((object)$"  HeroBox Collider: enabled={((Behaviour)component3).enabled}, isTrigger={component3.isTrigger}");
					}
				}
				Plugin.Log.LogInfo((object)"Hero Child Colliders:");
				array = ((Component)hero).GetComponentsInChildren<Collider2D>(true);
				foreach (Collider2D val2 in array)
				{
					if ((Object)(object)((Component)val2).gameObject != (Object)(object)((Component)hero).gameObject)
					{
						Plugin.Log.LogInfo((object)$"  - {((Object)((Component)val2).gameObject).name}: enabled={((Behaviour)val2).enabled}, active={((Component)val2).gameObject.activeInHierarchy}");
					}
				}
				Plugin.Log.LogInfo((object)"========== END HERO DEBUG LOG ==========");
				Plugin.Log.LogInfo((object)"[DEBUG] ApplyStateImmediate: Reset damageMode=FULL_DAMAGE, transitioning=false");
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("Failed to apply state: " + ex2.Message));
			}
		}

		private static void SaveStatesToDisk()
		{
			try
			{
				string contents = JsonConvert.SerializeObject((object)_saveStates, (Formatting)1);
				File.WriteAllText(_saveFilePath, contents);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to save states to disk: " + ex.Message));
			}
		}

		private static void LoadStatesFromDisk()
		{
			if (!File.Exists(_saveFilePath))
			{
				return;
			}
			try
			{
				List<SaveStateData> list = JsonConvert.DeserializeObject<List<SaveStateData>>(File.ReadAllText(_saveFilePath));
				if (list != null)
				{
					_saveStates = list;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to load states from disk: " + ex.Message));
			}
		}

		private static void LogAllEnemiesDetailed(string context)
		{
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Expected O, but got Unknown
			Plugin.Log.LogInfo((object)("========== ENEMY DEBUG LOG: " + context + " =========="));
			HealthManager[] array = Object.FindObjectsByType<HealthManager>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			Plugin.Log.LogInfo((object)$"Total enemies found: {array.Length}");
			HealthManager[] array2 = array;
			foreach (HealthManager val in array2)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null)
				{
					continue;
				}
				GameObject gameObject = ((Component)val).gameObject;
				Plugin.Log.LogInfo((object)("--- ENEMY: " + ((Object)gameObject).name + " ---"));
				Plugin.Log.LogInfo((object)("  Path: " + GetGameObjectPath(gameObject)));
				Plugin.Log.LogInfo((object)$"  Active: {gameObject.activeInHierarchy} (self={gameObject.activeSelf})");
				Plugin.Log.LogInfo((object)$"  HP: {val.hp}, IsDead: {val.isDead}, IsInvincible: {val.IsInvincible}");
				Plugin.Log.LogInfo((object)$"  Position: {gameObject.transform.position}");
				Component[] components = gameObject.GetComponents<Component>();
				Plugin.Log.LogInfo((object)$"  Components ({components.Length}):");
				Component[] array3 = components;
				foreach (Component val2 in array3)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string text = "";
					Behaviour val3 = (Behaviour)(object)((val2 is Behaviour) ? val2 : null);
					if (val3 != null)
					{
						text = $" [enabled={val3.enabled}]";
					}
					else
					{
						Collider2D val4 = (Collider2D)(object)((val2 is Collider2D) ? val2 : null);
						if (val4 != null)
						{
							text = $" [enabled={((Behaviour)val4).enabled}]";
						}
						else
						{
							Renderer val5 = (Renderer)(object)((val2 is Renderer) ? val2 : null);
							if (val5 != null)
							{
								text = $" [enabled={val5.enabled}]";
							}
						}
					}
					Plugin.Log.LogInfo((object)("    - " + ((object)val2).GetType().Name + text));
				}
				PlayMakerFSM[] components2 = gameObject.GetComponents<PlayMakerFSM>();
				if (components2.Length != 0)
				{
					Plugin.Log.LogInfo((object)$"  FSMs ({components2.Length}):");
					PlayMakerFSM[] array4 = components2;
					foreach (PlayMakerFSM val6 in array4)
					{
						Plugin.Log.LogInfo((object)$"    - {val6.FsmName}: state='{val6.ActiveStateName}', enabled={((Behaviour)val6).enabled}");
						if (val6.FsmVariables == null)
						{
							continue;
						}
						FsmBool[] boolVariables = val6.FsmVariables.BoolVariables;
						foreach (FsmBool val7 in boolVariables)
						{
							if (((NamedVariable)val7).Name.Contains("Spawn") || ((NamedVariable)val7).Name.Contains("Active") || ((NamedVariable)val7).Name.Contains("Dead") || ((NamedVariable)val7).Name.Contains("Alert") || ((NamedVariable)val7).Name.Contains("Hero") || ((NamedVariable)val7).Name.Contains("Seen"))
							{
								Plugin.Log.LogInfo((object)$"      {((NamedVariable)val7).Name} = {val7.Value}");
							}
						}
					}
				}
				Plugin.Log.LogInfo((object)$"  Children ({gameObject.transform.childCount}):");
				foreach (Transform item in gameObject.transform)
				{
					Transform val8 = item;
					string text2 = (((Component)val8).gameObject.activeInHierarchy ? "active" : "INACTIVE");
					Plugin.Log.LogInfo((object)("    - " + ((Object)val8).name + " [" + text2 + "]"));
				}
			}
			Plugin.Log.LogInfo((object)"========== END ENEMY DEBUG LOG ==========");
		}

		private static List<EnemyStateData> CaptureEnemyStates()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: 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_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Invalid comparison between Unknown and I4
			LogAllEnemiesDetailed("BEFORE CAPTURE");
			List<EnemyStateData> list = new List<EnemyStateData>();
			HealthManager[] array = Object.FindObjectsByType<HealthManager>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			Plugin.Log.LogInfo((object)$"[DEBUG] CaptureEnemyStates: Found {array.Length} enemies (including inactive)");
			HealthManager[] array2 = array;
			foreach (HealthManager val in array2)
			{
				if ((Object)(object)((Component)val).gameObject == (Object)null)
				{
					continue;
				}
				EnemyStateData enemyStateData = new EnemyStateData();
				enemyStateData.GameObjectName = ((Object)((Component)val).gameObject).name;
				enemyStateData.GameObjectPath = GetGameObjectPath(((Component)val).gameObject);
				enemyStateData.IsActive = ((Component)val).gameObject.activeInHierarchy;
				enemyStateData.HP = val.hp;
				enemyStateData.IsDead = val.isDead;
				enemyStateData.IsInvincible = val.IsInvincible;
				enemyStateData.InvincibleFromDirection = val.InvincibleFromDirection;
				enemyStateData.Position = ((Component)val).transform.position;
				enemyStateData.Rotation = ((Component)val).transform.rotation;
				enemyStateData.Scale = ((Component)val).transform.localScale;
				Rigidbody2D component = ((Component)val).GetComponent<Rigidbody2D>();
				if ((Object)(object)component != (Object)null)
				{
					enemyStateData.Velocity = component.linearVelocity;
					enemyStateData.AngularVelocity = component.angularVelocity;
					enemyStateData.IsKinematic = (int)component.bodyType == 1;
				}
				Recoil component2 = ((Component)val).GetComponent<Recoil>();
				if ((Object)(object)component2 != (Object)null)
				{
					FieldInfo field = typeof(Recoil).GetField("state", BindingFlags.Instance | BindingFlags.NonPublic);
					FieldInfo field2 = typeof(Recoil).GetField("recoilTimeRemaining", BindingFlags.Instance | BindingFlags.NonPublic);
					if (field != null)
					{
						object value = field.GetValue(component2);
						enemyStateData.IsRecoiling = (int)value == 2;
					}
					if (field2 != null)
					{
						enemyStateData.RecoilTimeRemaining = (float)field2.GetValue(component2);
					}
				}
				PlayMakerFSM[] components = ((Component)val).GetComponents<PlayMakerFSM>();
				foreach (PlayMakerFSM fsm in components)
				{
					enemyStateData.FsmStates.Add(CaptureFsmState(fsm));
				}
				enemyStateData.MainObjectState = CaptureObjectComponentData(((Component)val).gameObject);
				Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					if (!((Object)(object)val2 == (Object)(object)((Component)val).transform))
					{
						string relativePath = GetRelativePath(val2, ((Component)val).transform);
						enemyStateData.ChildStates[relativePath] = CaptureObjectComponentData(((Component)val2).gameObject);
					}
				}
				list.Add(enemyStateData);
			}
			return list;
		}

		private static FsmStateData CaptureFsmState(PlayMakerFSM fsm)
		{
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			FsmStateData fsmStateData = new FsmStateData();
			fsmStateData.FsmName = fsm.FsmName;
			fsmStateData.ActiveStateName = fsm.ActiveStateName;
			if (fsm.FsmVariables != null)
			{
				FsmBool[] boolVariables = fsm.FsmVariables.BoolVariables;
				foreach (FsmBool val in boolVariables)
				{
					fsmStateData.BoolVariables[((NamedVariable)val).Name] = val.Value;
				}
				FsmInt[] intVariables = fsm.FsmVariables.IntVariables;
				foreach (FsmInt val2 in intVariables)
				{
					fsmStateData.IntVariables[((NamedVariable)val2).Name] = val2.Value;
				}
				FsmFloat[] floatVariables = fsm.FsmVariables.FloatVariables;
				foreach (FsmFloat val3 in floatVariables)
				{
					fsmStateData.FloatVariables[((NamedVariable)val3).Name] = val3.Value;
				}
				FsmString[] stringVariables = fsm.FsmVariables.StringVariables;
				foreach (FsmString val4 in stringVariables)
				{
					fsmStateData.StringVariables[((NamedVariable)val4).Name] = val4.Value;
				}
				FsmVector3[] vector3Variables = fsm.FsmVariables.Vector3Variables;
				foreach (FsmVector3 val5 in vector3Variables)
				{
					fsmStateData.Vector3Variables[((NamedVariable)val5).Name] = val5.Value;
				}
			}
			return fsmStateData;
		}

		private static BattleSceneStateData CaptureBattleSceneState()
		{
			BattleScene val = Object.FindObjectOfType<BattleScene>();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			BattleSceneStateData battleSceneStateData = new BattleSceneStateData();
			battleSceneStateData.GameObjectPath = GetGameObjectPath(((Component)val).gameObject);
			battleSceneStateData.CurrentWave = val.currentWave;
			battleSceneStateData.CurrentEnemies = val.currentEnemies;
			battleSceneStateData.EnemiesToNext = val.enemiesToNext;
			FieldInfo field = typeof(BattleScene).GetField("started", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field != null)
			{
				battleSceneStateData.Started = (bool)(field.GetValue(val) ?? ((object)false));
			}
			Plugin.Log.LogInfo((object)$"[DEBUG] Captured BattleScene: wave={battleSceneStateData.CurrentWave}, enemies={battleSceneStateData.CurrentEnemies}, started={battleSceneStateData.Started}");
			return battleSceneStateData;
		}

		private static BossSceneStateData CaptureBossSceneState()
		{
			BossSceneController val = Object.FindObjectOfType<BossSceneController>();
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			return new BossSceneStateData
			{
				IsActive = true,
				BossLevel = val.BossLevel,
				HasTransitionedIn = val.HasTransitionedIn
			};
		}

		private static void RestoreEnemyStates(List<EnemyStateData> enemyStates)
		{
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: 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_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Expected O, but got Unknown
			if (enemyStates == null)
			{
				return;
			}
			LogAllEnemiesDetailed("BEFORE RESTORE");
			HealthManager[] array = Object.FindObjectsByType<HealthManager>((FindObjectsInactive)1, (FindObjectsSortMode)0);
			Plugin.Log.LogInfo((object)$"[DEBUG] RestoreEnemyStates: Found {array.Length} enemies to restore from {enemyStates.Count} saved states");
			foreach (EnemyStateData state in enemyStates)
			{
				HealthManager val = ((IEnumerable<HealthManager>)array).FirstOrDefault((Func<HealthManager, bool>)((HealthManager e) => GetGameObjectPath(((Component)e).gameObject) == state.GameObjectPath));
				if ((Object)(object)val == (Object)null)
				{
					Plugin.Log.LogWarning((object)("Could not find enemy to restore: " + state.GameObjectPath));
					continue;
				}
				((Component)val).gameObject.SetActive(state.IsActive);
				Plugin.Log.LogInfo((object)$"[DEBUG] Restored enemy '{state.GameObjectName}' active={state.IsActive}");
				val.hp = state.HP;
				val.isDead = state.IsDead;
				val.IsInvincible = state.IsInvincible;
				val.InvincibleFromDirection = state.InvincibleFromDirection;
				((Component)val).transform.position = state.Position;
				((Component)val).transform.rotation = state.Rotation;
				((Component)val).transform.localScale = state.Scale;
				Rigidbody2D component = ((Component)val).GetComponent<Rigidbody2D>();
				if ((Object)(object)component != (Object)null)
				{
					component.linearVelocity = state.Velocity;
					component.angularVelocity = state.AngularVelocity;
					if (state.IsKinematic)
					{
						component.bodyType = (RigidbodyType2D)1;
					}
				}
				Recoil component2 = ((Component)val).GetComponent<Recoil>();
				if ((Object)(object)component2 != (Object)null)
				{
					if (state.IsRecoiling)
					{
						typeof(Recoil).GetField("state", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(component2, 2);
						typeof(Recoil).GetField("recoilTimeRemaining", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(component2, state.RecoilTimeRemaining);
					}
					else
					{
						typeof(Recoil).GetField("state", BindingFlags.Instance | BindingFlags.NonPublic)?.SetValue(component2, 0);
						component2.CancelRecoil();
					}
				}
				PlayMakerFSM[] components = ((Component)val).GetComponents<PlayMakerFSM>();
				foreach (FsmStateData fsmData in state.FsmStates)
				{
					PlayMakerFSM val2 = ((IEnumerable<PlayMakerFSM>)components).FirstOrDefault((Func<PlayMakerFSM, bool>)((PlayMakerFSM f) => f.FsmName == fsmData.FsmName));
					if ((Object)(object)val2 != (Object)null)
					{
						RestoreFsmSta