using 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.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.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Silk Song Death Swap")]
[assembly: AssemblyTitle("SilkSongDeathSwap")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.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()
{
ShowWindow(GetForegroundWindow(), 6);
}
public static void RestoreWindow()
{
ShowWindow(GetForegroundWindow(), 9);
}
}
[BepInPlugin("SilkSongDeathSwap", "Silk Song Death Swap", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
private Harmony _harmony;
public static bool gameStarted = false;
public static bool gamePaused = false;
private static Thread listenerThread;
private static volatile bool keepListening = true;
private void Awake()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"Plugin SilkSongDeathSwap is loaded!");
_harmony = new Harmony("SilkSongDeathSwap");
_harmony.PatchAll();
}
private void Update()
{
if (Input.GetKeyDown((KeyCode)287) && gameStarted)
{
if (gamePaused)
{
Logger.LogInfo((object)"F6 pressed: Resuming game.");
ResumeGame();
gamePaused = false;
}
else
{
Logger.LogInfo((object)"F6 pressed: Pausing game.");
PauseGame();
gamePaused = true;
}
}
}
private static void EnableControl(bool enable)
{
HeroController instance = HeroController.instance;
if ((Object)(object)instance != (Object)null)
{
if (enable)
{
instance.RegainControl();
ManagerSingleton<InputHandler>.Instance.StartAcceptingInput();
}
else
{
instance.RelinquishControl();
ManagerSingleton<InputHandler>.Instance.StopAcceptingInput();
}
}
}
public static void PauseGame()
{
Time.timeScale = 0f;
AudioListener.pause = true;
EnableControl(enable: false);
}
public static void ResumeGame()
{
Time.timeScale = 1f;
AudioListener.pause = false;
Screen.fullScreen = true;
WinAPI.RestoreWindow();
EnableControl(enable: true);
}
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();
}
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(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();
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.0.0";
}
}