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 PreviousStates = new Dictionary(); 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 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 _toggleKey; private ConfigEntry _pauseAudio; private ConfigEntry _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("Controls", "ToggleKey", (KeyCode)112, "Key used to toggle pausing in solo games."); _pauseAudio = ((BaseUnityPlugin)this).Config.Bind("Pause", "PauseAudio", true, "Mute game audio while the solo pause is active."); _showOverlay = ((BaseUnityPlugin)this).Config.Bind("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)SemiFunc.IsMainMenu) || SafeGameCheck((Func)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)SemiFunc.NoTextInputsActive); } catch { return true; } } private static bool SafeGameCheck(Func 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); } } }