Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SSManager v1.0.1
BepInEx/plugins/SilksongManager.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
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