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 Hollow Knight Death Swap for Silksong v1.2.1
SilkSongDeathSwap.dll
Decompiled 8 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SilkSongDeathSwap")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.2.1.0")] [assembly: AssemblyInformationalVersion("1.2.1")] [assembly: AssemblyProduct("Silk Song Death Swap")] [assembly: AssemblyTitle("SilkSongDeathSwap")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SilkSongSwitcher { internal static class WinAPI { private const int SW_MINIMIZE = 6; private const int SW_RESTORE = 9; [DllImport("user32.dll")] private static extern int ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); public static void MinimizeWindow() { IntPtr mainWindowHandleFallback = GetMainWindowHandleFallback(); ShowWindow(mainWindowHandleFallback, 6); } public static void RestoreWindow() { IntPtr mainWindowHandleFallback = GetMainWindowHandleFallback(); ShowWindow(mainWindowHandleFallback, 9); } private static IntPtr GetMainWindowHandleFallback() { try { Process currentProcess = Process.GetCurrentProcess(); if (currentProcess != null && currentProcess.MainWindowHandle != IntPtr.Zero) { return currentProcess.MainWindowHandle; } } catch { } return GetForegroundWindow(); } } [BepInPlugin("SilkSongDeathSwap", "Silk Song Death Swap", "1.2.1")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger; private Harmony _harmony; public static bool gameStarted; public static bool gamePaused; public static bool switchOnDamage; public static bool damageTaken; private static Thread listenerThread; private static volatile bool keepListening; private static InputHandler inputHandler; private ConfigEntry<bool> cfgSwitchOnDamage; private ConfigEntry<KeyboardShortcut> cfgPauseToggleKey; private ConfigEntry<KeyboardShortcut> cfgSwitchOnDamageToggleKey; private void Awake() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown Logger = ((BaseUnityPlugin)this).Logger; Logger.LogInfo((object)"Plugin SilkSongDeathSwap is loaded!"); cfgSwitchOnDamage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "SwitchOnDamage", false, "If true, switching occurs when player takes damage."); cfgPauseToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "TogglePauseResumeKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Key used to toggle pause/resume."); cfgSwitchOnDamageToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "ToggleSwitchOnDamageKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Key used to toggle switch on damage."); switchOnDamage = cfgSwitchOnDamage.Value; cfgSwitchOnDamage.SettingChanged += delegate { switchOnDamage = cfgSwitchOnDamage.Value; }; _harmony = new Harmony("SilkSongDeathSwap"); _harmony.PatchAll(); } private void Update() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0081: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value; if (gameStarted) { value = cfgPauseToggleKey.Value; if (Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey)) { if (gamePaused) { ManualLogSource logger = Logger; value = cfgPauseToggleKey.Value; logger.LogInfo((object)$"{((KeyboardShortcut)(ref value)).MainKey} pressed: Resuming game."); ResumeGame(); } else { ManualLogSource logger2 = Logger; value = cfgPauseToggleKey.Value; logger2.LogInfo((object)$"{((KeyboardShortcut)(ref value)).MainKey} pressed: Pausing game."); PauseGame(); } } } if (gameStarted) { value = cfgSwitchOnDamageToggleKey.Value; if (Input.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey)) { if (!switchOnDamage) { ManualLogSource logger3 = Logger; value = cfgSwitchOnDamageToggleKey.Value; logger3.LogInfo((object)$"{((KeyboardShortcut)(ref value)).MainKey} pressed: Enabling switch on damage."); switchOnDamage = true; } else { ManualLogSource logger4 = Logger; value = cfgSwitchOnDamageToggleKey.Value; logger4.LogInfo((object)$"{((KeyboardShortcut)(ref value)).MainKey} pressed: Disabling switch on damage."); switchOnDamage = false; } } } if (gameStarted && gamePaused) { inputHandler = ManagerSingleton<InputHandler>.Instance; if ((Object)(object)inputHandler != (Object)null) { inputHandler.StopAcceptingInput(); inputHandler.PreventPause(); } Time.timeScale = 0f; } } public static void PauseGame() { gamePaused = true; AudioListener.pause = true; Logger.LogInfo((object)"Game paused."); } public static void ResumeGame() { gamePaused = false; Time.timeScale = 1f; AudioListener.pause = false; WinAPI.RestoreWindow(); if (damageTaken) { damageTaken = false; } inputHandler = ManagerSingleton<InputHandler>.Instance; if ((Object)(object)inputHandler != (Object)null) { Logger.LogInfo((object)"Resuming input handling."); inputHandler.StartAcceptingInput(); inputHandler.AllowPause(); } } public static void SendMessageToHollowKnight(string message) { try { using TcpClient tcpClient = new TcpClient("127.0.0.1", 5001); using NetworkStream networkStream = tcpClient.GetStream(); byte[] bytes = Encoding.UTF8.GetBytes(message); networkStream.Write(bytes, 0, bytes.Length); byte[] array = new byte[1024]; int count = networkStream.Read(array, 0, array.Length); string @string = Encoding.UTF8.GetString(array, 0, count); Logger.LogInfo((object)("Received from Hollow Knight: " + @string)); } catch (Exception ex) { Logger.LogInfo((object)("TCP Error: " + ex.Message)); } } public static void StartListeningToHollowKnight() { keepListening = true; listenerThread = new Thread(ListenForHollowKnightMessages); listenerThread.IsBackground = true; listenerThread.Start(); } public static void StopListeningToHollowKnight() { keepListening = false; listenerThread?.Join(); } private static void ListenForHollowKnightMessages() { TcpListener tcpListener = null; try { tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 5002); tcpListener.Start(); Logger.LogInfo((object)"Listening for Hollow Knight messages on port 5002..."); while (keepListening) { if (tcpListener.Pending()) { using TcpClient tcpClient = tcpListener.AcceptTcpClient(); using NetworkStream networkStream = tcpClient.GetStream(); byte[] array = new byte[1024]; int num = networkStream.Read(array, 0, array.Length); if (num > 0) { string @string = Encoding.UTF8.GetString(array, 0, num); Logger.LogInfo((object)("Received from Hollow Knight: " + @string)); if (@string == "resume_game") { ResumeGame(); } if (@string == "pause_game") { PauseGame(); } if (@string == "enable_switch_on_damage") { switchOnDamage = true; Logger.LogInfo((object)"Switch on damage enabled."); } byte[] bytes = Encoding.UTF8.GetBytes("ACK"); networkStream.Write(bytes, 0, bytes.Length); } } Thread.Sleep(100); } } catch (Exception ex) { Logger.LogInfo((object)("TCP Listen Error: " + ex.Message)); } finally { tcpListener?.Stop(); } } } [HarmonyPatch(typeof(GameManager), "RespawningHero")] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public static class GameManager_RespawningHero_Set_Patch { public static void Prefix(bool value) { if (value && Plugin.gameStarted) { Plugin.Logger.LogInfo((object)"Player death detected: RespawningHero set to true."); Plugin.SendMessageToHollowKnight("resume_game"); Plugin.PauseGame(); } } } [HarmonyPatch(typeof(HeroController), "Invulnerable")] public static class HeroController_Invulnerable_Patch { [CompilerGenerated] private sealed class <WrapCoroutine>d__1 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator original; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WrapCoroutine>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (original.MoveNext()) { <>2__current = original.Current; <>1__state = 1; return true; } if (Plugin.switchOnDamage && Plugin.gameStarted) { Plugin.Logger.LogInfo((object)"Player damage detected: Invulnerable coroutine completed."); Plugin.PauseGame(); Plugin.SendMessageToHollowKnight("resume_game"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void Postfix(ref IEnumerator __result) { __result = WrapCoroutine(__result); } [IteratorStateMachine(typeof(<WrapCoroutine>d__1))] private static IEnumerator WrapCoroutine(IEnumerator original) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WrapCoroutine>d__1(0) { original = original }; } } [HarmonyPatch(typeof(GameManager), "RunContinueGame", new Type[] { typeof(bool) })] public static class GameManager_RunContinueGame_Get_Patch { [CompilerGenerated] private sealed class <WrapCoroutine>d__1 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerator original; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <WrapCoroutine>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if (original.MoveNext()) { <>2__current = original.Current; <>1__state = 1; return true; } Plugin.Logger.LogInfo((object)"Game start detected: RunContinueGame completed."); Plugin.gameStarted = true; Plugin.StartListeningToHollowKnight(); if (Plugin.switchOnDamage) { Plugin.SendMessageToHollowKnight("enable_switch_on_damage"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public static void Postfix(ref IEnumerator __result) { __result = WrapCoroutine(__result); } [IteratorStateMachine(typeof(<WrapCoroutine>d__1))] private static IEnumerator WrapCoroutine(IEnumerator original) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WrapCoroutine>d__1(0) { original = original }; } } [HarmonyPatch(typeof(GameManager), "ReturnToMainMenu", new Type[] { typeof(bool), typeof(Action<bool>), typeof(bool), typeof(bool) })] public static class GameManager_ReturnToMainMenu_Patch { public static void Postfix() { Plugin.Logger.LogInfo((object)"Return to Main Menu detected."); Plugin.gameStarted = false; Plugin.StopListeningToHollowKnight(); } } [HarmonyPatch(typeof(HeroController), "CanOpenInventory")] public static class HeroController_CanOpenInventory_Patch { public static bool Prefix(ref bool __result) { if (Plugin.gamePaused) { __result = false; return false; } return true; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "SilkSongDeathSwap"; public const string PLUGIN_NAME = "Silk Song Death Swap"; public const string PLUGIN_VERSION = "1.2.1"; } }