Decompiled source of SoloPause v1.0.1

BepInEx\plugins\MechGaming-SoloPause\SoloPause.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("MechGaming")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("SoloPause")]
[assembly: AssemblyTitle("SoloPause")]
[assembly: AssemblyVersion("1.0.1.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace MechGaming.REPO.SoloPause
{
	internal static class HotkeyInput
	{
		private const int KeyDownMask = 32768;

		private const float TextInputScanInterval = 0.15f;

		private static readonly Dictionary<KeyCode, bool> PreviousStates = new Dictionary<KeyCode, bool>();

		private static readonly Type? UnityInputFieldType = Type.GetType("UnityEngine.UI.InputField, UnityEngine.UI");

		private static readonly Type? TmpInputFieldType = Type.GetType("TMPro.TMP_InputField, Unity.TextMeshPro");

		private static int _currentProcessId;

		private static float _nextTextInputScanTime;

		private static bool _cachedNoTextInputActive = true;

		private static int CurrentProcessId
		{
			get
			{
				if (_currentProcessId == 0)
				{
					_currentProcessId = Process.GetCurrentProcess().Id;
				}
				return _currentProcessId;
			}
		}

		internal static bool GetKeyDown(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			bool flag = GetUnityKeyDown(key) || GetWindowsKey(key);
			bool value;
			bool flag2 = PreviousStates.TryGetValue(key, out value) && value;
			PreviousStates[key] = flag;
			if (flag)
			{
				return !flag2;
			}
			return false;
		}

		internal static bool NoTextInputActive(Func<bool> gameCheck)
		{
			try
			{
				if (gameCheck())
				{
					_cachedNoTextInputActive = true;
					return true;
				}
			}
			catch
			{
			}
			if (Time.unscaledTime < _nextTextInputScanTime)
			{
				return _cachedNoTextInputActive;
			}
			_nextTextInputScanTime = Time.unscaledTime + 0.15f;
			_cachedNoTextInputActive = !AnyFocusedTextInput();
			return _cachedNoTextInputActive;
		}

		private static bool GetUnityKeyDown(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				return Input.GetKeyDown(key);
			}
			catch
			{
				return false;
			}
		}

		private static bool GetWindowsKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			int num = ToVirtualKey(key);
			if (num != 0 && IsForegroundProcess())
			{
				return IsVirtualKeyDown(num);
			}
			return false;
		}

		private static bool IsVirtualKeyDown(int virtualKey)
		{
			try
			{
				return (GetAsyncKeyState(virtualKey) & 0x8000) != 0;
			}
			catch
			{
				return false;
			}
		}

		private static bool IsForegroundProcess()
		{
			try
			{
				IntPtr foregroundWindow = GetForegroundWindow();
				if (foregroundWindow == IntPtr.Zero)
				{
					return false;
				}
				GetWindowThreadProcessId(foregroundWindow, out var processId);
				return processId == CurrentProcessId;
			}
			catch
			{
				return false;
			}
		}

		private static int ToVirtualKey(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected I4, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected I4, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected I4, but got Unknown
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Invalid comparison between Unknown and I4
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Invalid comparison between Unknown and I4
			//IL_00bc: 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_00e0: Expected I4, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected I4, but got Unknown
			if ((int)key >= 97 && (int)key <= 122)
			{
				return 65 + (key - 97);
			}
			if ((int)key >= 48 && (int)key <= 57)
			{
				return 48 + (key - 48);
			}
			if ((int)key >= 282 && (int)key <= 678)
			{
				return 112 + (key - 282);
			}
			if ((int)key <= 27)
			{
				if ((int)key <= 9)
				{
					if ((int)key == 8)
					{
						return 8;
					}
					if ((int)key == 9)
					{
						return 9;
					}
				}
				else
				{
					if ((int)key == 13)
					{
						return 13;
					}
					if ((int)key == 27)
					{
						return 27;
					}
				}
			}
			else if ((int)key <= 127)
			{
				if ((int)key == 32)
				{
					return 32;
				}
				if ((int)key == 127)
				{
					return 46;
				}
			}
			else
			{
				switch (key - 273)
				{
				case 7:
					return 33;
				case 8:
					return 34;
				case 6:
					return 35;
				case 5:
					return 36;
				case 3:
					return 37;
				case 0:
					return 38;
				case 2:
					return 39;
				case 1:
					return 40;
				case 4:
					return 45;
				}
				switch (key - 303)
				{
				case 1:
					return 160;
				case 0:
					return 161;
				case 3:
					return 162;
				case 2:
					return 163;
				case 5:
					return 164;
				case 4:
					return 165;
				}
				switch (key - 323)
				{
				case 0:
					return 1;
				case 1:
					return 2;
				case 2:
					return 4;
				}
			}
			return 0;
		}

		private static bool AnyFocusedTextInput()
		{
			if (!TypeHasFocusedInput(UnityInputFieldType))
			{
				return TypeHasFocusedInput(TmpInputFieldType);
			}
			return true;
		}

		private static bool TypeHasFocusedInput(Type? inputType)
		{
			if (inputType == null)
			{
				return false;
			}
			try
			{
				Object[] array = Resources.FindObjectsOfTypeAll(inputType);
				for (int i = 0; i < array.Length; i++)
				{
					if (IsFocusedInput(array[i]))
					{
						return true;
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		private static bool IsFocusedInput(Object input)
		{
			Component val = (Component)(object)((input is Component) ? input : null);
			if (val == null || !val.gameObject.activeInHierarchy)
			{
				return false;
			}
			Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
			if (val2 != null && !val2.enabled)
			{
				return false;
			}
			PropertyInfo property = ((object)input).GetType().GetProperty("isFocused", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (property != null && property.PropertyType == typeof(bool))
			{
				try
				{
					return (bool)property.GetValue(input, null);
				}
				catch
				{
					return false;
				}
			}
			return false;
		}

		[DllImport("user32.dll")]
		private static extern short GetAsyncKeyState(int virtualKey);

		[DllImport("user32.dll")]
		private static extern IntPtr GetForegroundWindow();

		[DllImport("user32.dll")]
		private static extern uint GetWindowThreadProcessId(IntPtr windowHandle, out uint processId);
	}
	[BepInPlugin("MechGaming.REPO.SoloPause", "SoloPause", "1.0.1")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "MechGaming.REPO.SoloPause";

		public const string PluginName = "SoloPause";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<KeyCode> _toggleKey;

		private ConfigEntry<bool> _pauseAudio;

		private ConfigEntry<bool> _showOverlay;

		private bool _paused;

		private bool _previousAudioPause;

		private bool _previousCursorVisible;

		private CursorLockMode _previousCursorLockState;

		private float _previousTimeScale = 1f;

		private void Awake()
		{
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ToggleKey", (KeyCode)112, "Key used to toggle pausing in solo games.");
			_pauseAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("Pause", "PauseAudio", true, "Mute game audio while the solo pause is active.");
			_showOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Pause", "ShowOverlay", true, "Show a small paused message while the solo pause is active.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SoloPause 1.0.1 loaded.");
		}

		private void Update()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (_paused && !CanStayPaused())
			{
				Resume("Auto-unpaused because the game is no longer a solo run.");
			}
			else if (HotkeyInput.GetKeyDown(_toggleKey.Value))
			{
				if (_paused)
				{
					Resume("Unpaused.");
				}
				else if (CanPauseNow())
				{
					Pause();
				}
			}
		}

		private void LateUpdate()
		{
			if (_paused)
			{
				ApplyPausedState();
			}
		}

		private void OnDestroy()
		{
			if (_paused)
			{
				Resume("Unpaused during plugin shutdown.");
			}
		}

		private void OnGUI()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			if (_paused && _showOverlay.Value)
			{
				Rect val = default(Rect);
				((Rect)(ref val))..ctor((float)(Screen.width - 360) / 2f, 48f, 360f, 110f);
				GUI.color = new Color(0f, 0f, 0f, 0.68f);
				GUI.Box(val, GUIContent.none);
				GUI.color = Color.white;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 34,
					fontStyle = (FontStyle)1
				};
				val2.normal.textColor = Color.white;
				GUIStyle val3 = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 15
				};
				val3.normal.textColor = new Color(0.9f, 0.95f, 1f, 1f);
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 18f, ((Rect)(ref val)).width, 42f), "PAUSED", val2);
				GUI.Label(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y + 64f, ((Rect)(ref val)).width, 24f), $"Press {_toggleKey.Value} to resume", val3);
			}
		}

		private bool CanPauseNow()
		{
			if (CanStayPaused())
			{
				return NoTextInputActive();
			}
			return false;
		}

		private static bool CanStayPaused()
		{
			if (IsMultiplayer())
			{
				return false;
			}
			if ((Object)(object)GameDirector.instance == (Object)null || (Object)(object)PlayerController.instance == (Object)null)
			{
				return false;
			}
			if (SafeGameCheck((Func<bool>)SemiFunc.IsMainMenu) || SafeGameCheck((Func<bool>)SemiFunc.RunIsLobbyMenu))
			{
				return false;
			}
			return true;
		}

		private static bool IsMultiplayer()
		{
			try
			{
				return (Object)(object)GameManager.instance != (Object)null && GameManager.Multiplayer();
			}
			catch
			{
				return false;
			}
		}

		private static bool NoTextInputActive()
		{
			try
			{
				return HotkeyInput.NoTextInputActive((Func<bool>)SemiFunc.NoTextInputsActive);
			}
			catch
			{
				return true;
			}
		}

		private static bool SafeGameCheck(Func<bool> check)
		{
			try
			{
				return check();
			}
			catch
			{
				return false;
			}
		}

		private void Pause()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			_previousTimeScale = ((Time.timeScale > 0f) ? Time.timeScale : 1f);
			_previousAudioPause = AudioListener.pause;
			_previousCursorVisible = Cursor.visible;
			_previousCursorLockState = Cursor.lockState;
			_paused = true;
			ApplyPausedState();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Paused solo game.");
		}

		private void ApplyPausedState()
		{
			Time.timeScale = 0f;
			if (_pauseAudio.Value)
			{
				AudioListener.pause = true;
			}
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
		}

		private void Resume(string logMessage)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			Time.timeScale = ((_previousTimeScale > 0f) ? _previousTimeScale : 1f);
			if (_pauseAudio.Value)
			{
				AudioListener.pause = _previousAudioPause;
			}
			Cursor.visible = _previousCursorVisible;
			Cursor.lockState = _previousCursorLockState;
			_paused = false;
			((BaseUnityPlugin)this).Logger.LogInfo((object)logMessage);
		}
	}
}