Decompiled source of NoBackgroundHover v1.0.0

BepInEx/plugins/NoBackgroundHover/NoBackgroundHover.dll

Decompiled 5 hours ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;

[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("Zenoyui")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Zenoyui")]
[assembly: AssemblyDescription("Stops REPO menu hover input while the game window is not focused.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NoBackgroundHover")]
[assembly: AssemblyTitle("NoBackgroundHover")]
[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.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 NoBackgroundHover
{
	[BepInPlugin("ru.zenoyui.NoBackgroundHover", "No Background Hover", "1.0.0")]
	public sealed class NoBackgroundHoverPlugin : BaseUnityPlugin
	{
		private static class UiMouseHoverPatch
		{
			public static bool Prefix(ref bool __result)
			{
				if (FocusGate.UiInputAllowed)
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		private static class AllowOnlyFocusedPatch
		{
			public static bool Prefix()
			{
				return FocusGate.UiInputAllowed;
			}
		}

		private sealed class FocusLoop : MonoBehaviour
		{
			private bool _wasAllowed = true;

			private float _nextClear;

			private void Update()
			{
				bool uiInputAllowed = FocusGate.UiInputAllowed;
				if (!uiInputAllowed && (_wasAllowed || Time.unscaledTime >= _nextClear))
				{
					_nextClear = Time.unscaledTime + 0.25f;
					ClearHoverState();
				}
				_wasAllowed = uiInputAllowed;
			}

			private void OnApplicationFocus(bool focus)
			{
				FocusGate.Invalidate();
				if (!focus)
				{
					ClearHoverState();
				}
			}

			private void OnApplicationPause(bool pause)
			{
				FocusGate.Invalidate();
				if (pause)
				{
					ClearHoverState();
				}
			}
		}

		private static class FocusGate
		{
			private static readonly uint CurrentProcessId = (uint)Process.GetCurrentProcess().Id;

			private static int _cachedFrame = -1;

			private static bool _cachedAllowed = true;

			public static bool UiInputAllowed
			{
				get
				{
					int frameCount = Time.frameCount;
					if (_cachedFrame == frameCount)
					{
						return _cachedAllowed;
					}
					_cachedFrame = frameCount;
					_cachedAllowed = ReadFocusState();
					return _cachedAllowed;
				}
			}

			public static void Invalidate()
			{
				_cachedFrame = -1;
			}

			private static bool ReadFocusState()
			{
				if (!Application.isFocused)
				{
					return false;
				}
				if (!IsWindowsPlayer())
				{
					return true;
				}
				if (!TryGetForegroundProcessId(out var processId))
				{
					return true;
				}
				return processId == CurrentProcessId;
			}

			private static bool IsWindowsPlayer()
			{
				//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_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Invalid comparison between Unknown and I4
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Invalid comparison between Unknown and I4
				RuntimePlatform platform = Application.platform;
				if ((int)platform != 2)
				{
					return (int)platform == 7;
				}
				return true;
			}

			private static bool TryGetForegroundProcessId(out uint processId)
			{
				processId = 0u;
				try
				{
					IntPtr foregroundWindow = GetForegroundWindow();
					if (foregroundWindow == IntPtr.Zero)
					{
						return false;
					}
					GetWindowThreadProcessId(foregroundWindow, out processId);
					return processId != 0;
				}
				catch
				{
					processId = 0u;
					return false;
				}
			}

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

			[DllImport("user32.dll")]
			private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
		}

		private const string PluginGuid = "ru.zenoyui.NoBackgroundHover";

		private const string PluginName = "No Background Hover";

		private const string PluginVersion = "1.0.0";

		private static ManualLogSource Log;

		private static Harmony _harmony;

		private static Type? _menuManagerType;

		private static Type? _menuButtonType;

		private static Type? _menuElementHoverType;

		private static Type? _menuSliderType;

		private static Type? _menuSelectionBoxType;

		private static FieldInfo? _menuManagerInstanceField;

		private static FieldInfo? _currentMenuIdField;

		private static FieldInfo? _mouseHoldPositionField;

		private static FieldInfo? _menuHoverField;

		private static FieldInfo? _menuButtonHoveringField;

		private static FieldInfo? _menuButtonHoverTimerField;

		private static FieldInfo? _menuButtonClickedField;

		private static FieldInfo? _menuButtonClickTimerField;

		private static FieldInfo? _menuButtonStateField;

		private static FieldInfo? _menuElementIsHoveringField;

		private static FieldInfo? _menuSliderHoveringField;

		private static FieldInfo? _selectionBoxActiveTargetTimerField;

		private static FieldInfo? _selectionBoxClickTimerField;

		private static MethodInfo? _menuButtonPointerExitMethod;

		private void Awake()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("ru.zenoyui.NoBackgroundHover");
			CacheGameFields();
			PatchGameHover();
			PatchUnityEventSystem();
			GameObject val = new GameObject("NoBackgroundHover.FocusLoop");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<FocusLoop>();
			Log.LogInfo((object)"mod: init (id=ru.zenoyui.NoBackgroundHover, ver=1.0.0)");
		}

		private static void CacheGameFields()
		{
			_menuManagerType = AccessTools.TypeByName("MenuManager");
			_menuButtonType = AccessTools.TypeByName("MenuButton");
			_menuElementHoverType = AccessTools.TypeByName("MenuElementHover");
			_menuSliderType = AccessTools.TypeByName("MenuSlider");
			_menuSelectionBoxType = AccessTools.TypeByName("MenuSelectionBox");
			_menuManagerInstanceField = Field(_menuManagerType, "instance");
			_currentMenuIdField = Field(_menuManagerType, "currentMenuID");
			_mouseHoldPositionField = Field(_menuManagerType, "mouseHoldPosition");
			_menuHoverField = Field(_menuManagerType, "menuHover");
			_menuButtonHoveringField = Field(_menuButtonType, "hovering");
			_menuButtonHoverTimerField = Field(_menuButtonType, "hoverTimer");
			_menuButtonClickedField = Field(_menuButtonType, "clicked");
			_menuButtonClickTimerField = Field(_menuButtonType, "clickTimer");
			_menuButtonStateField = Field(_menuButtonType, "buttonState");
			_menuButtonPointerExitMethod = Method(_menuButtonType, "OnPointerExit", typeof(PointerEventData));
			_menuElementIsHoveringField = Field(_menuElementHoverType, "isHovering");
			_menuSliderHoveringField = Field(_menuSliderType, "hovering");
			_selectionBoxActiveTargetTimerField = Field(_menuSelectionBoxType, "activeTargetTimer");
			_selectionBoxClickTimerField = Field(_menuSelectionBoxType, "clickTimer");
		}

		private static FieldInfo? Field(Type? type, string name)
		{
			if (!(type == null))
			{
				return AccessTools.Field(type, name);
			}
			return null;
		}

		private static MethodInfo? Method(Type? type, string name, params Type[] args)
		{
			if (!(type == null))
			{
				return AccessTools.Method(type, name, args, (Type[])null);
			}
			return null;
		}

		private static void PatchGameHover()
		{
			Type type = AccessTools.TypeByName("SemiFunc");
			Type type2 = AccessTools.TypeByName("MenuPage");
			MethodInfo methodInfo = null;
			if (type != null && type2 != null)
			{
				methodInfo = AccessTools.Method(type, "UIMouseHover", new Type[5]
				{
					type2,
					typeof(RectTransform),
					typeof(string),
					typeof(float),
					typeof(float)
				}, (Type[])null);
			}
			if (methodInfo == null)
			{
				methodInfo = Method(type, "UIMouseHover");
			}
			PatchPrefix(methodInfo, typeof(UiMouseHoverPatch), "Prefix", "SemiFunc.UIMouseHover", required: true);
			PatchPrefix(Method(type, "MenuSelectionBoxTargetSet"), typeof(AllowOnlyFocusedPatch), "Prefix", "SemiFunc.MenuSelectionBoxTargetSet", required: false);
			PatchPrefix(Method(_menuManagerType, "MenuEffectHover"), typeof(AllowOnlyFocusedPatch), "Prefix", "MenuManager.MenuEffectHover", required: false);
			PatchPrefix(Method(_menuButtonType, "OnPointerEnter", typeof(PointerEventData)), typeof(AllowOnlyFocusedPatch), "Prefix", "MenuButton.OnPointerEnter", required: false);
			PatchPrefix(Method(_menuButtonType, "OnPointerClick", typeof(PointerEventData)), typeof(AllowOnlyFocusedPatch), "Prefix", "MenuButton.OnPointerClick", required: false);
		}

		private static void PatchUnityEventSystem()
		{
			PatchProcess("UnityEngine.EventSystems.StandaloneInputModule");
			PatchProcess("UnityEngine.EventSystems.TouchInputModule");
			PatchProcess("UnityEngine.InputSystem.UI.InputSystemUIInputModule");
		}

		private static void PatchProcess(string typeName)
		{
			PatchPrefix(Method(AccessTools.TypeByName(typeName), "Process"), typeof(AllowOnlyFocusedPatch), "Prefix", typeName + ".Process", required: false);
		}

		private static void PatchPrefix(MethodInfo? original, Type patchType, string patchName, string label, bool required)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(patchType, patchName, (Type[])null, (Type[])null);
				if (original == null || methodInfo == null)
				{
					if (required)
					{
						Log.LogWarning((object)("patch: missing (target=" + label + ")"));
					}
					else
					{
						Log.LogInfo((object)("patch: skip (target=" + label + ")"));
					}
				}
				else
				{
					_harmony.Patch((MethodBase)original, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Log.LogInfo((object)("patch: ok (target=" + label + ")"));
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("patch: fail (target=" + label + ", err=" + ex.GetType().Name + ", msg=" + ex.Message + ")"));
			}
		}

		private static void ClearHoverState()
		{
			ClearEventSystem();
			ClearMenuManager();
			ClearObjects(_menuButtonType, ClearMenuButton);
			ClearObjects(_menuElementHoverType, ClearMenuElementHover);
			ClearObjects(_menuSliderType, ClearMenuSlider);
			ClearObjects(_menuSelectionBoxType, ClearMenuSelectionBox);
		}

		private static void ClearEventSystem()
		{
			try
			{
				EventSystem current = EventSystem.current;
				if ((Object)(object)current != (Object)null)
				{
					current.SetSelectedGameObject((GameObject)null);
				}
			}
			catch
			{
			}
		}

		private static void ClearMenuManager()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object obj = _menuManagerInstanceField?.GetValue(null);
				if (obj != null)
				{
					_currentMenuIdField?.SetValue(obj, "");
					_mouseHoldPositionField?.SetValue(obj, Vector2.zero);
					_menuHoverField?.SetValue(obj, 0f);
				}
			}
			catch
			{
			}
		}

		private static void ClearObjects(Type? type, Action<object> clear)
		{
			if (type == null)
			{
				return;
			}
			Object[] array;
			try
			{
				array = Resources.FindObjectsOfTypeAll(type);
			}
			catch
			{
				return;
			}
			Object[] array2 = array;
			foreach (Object val in array2)
			{
				if (val != (Object)null && IsSceneObject(val))
				{
					try
					{
						clear(val);
					}
					catch
					{
					}
				}
			}
		}

		private static bool IsSceneObject(Object obj)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Component val = (Component)(object)((obj is Component) ? obj : null);
			if (val != null)
			{
				Scene scene = val.gameObject.scene;
				return ((Scene)(ref scene)).IsValid();
			}
			GameObject val2 = (GameObject)(object)((obj is GameObject) ? obj : null);
			if (val2 != null)
			{
				Scene scene2 = val2.scene;
				return ((Scene)(ref scene2)).IsValid();
			}
			return false;
		}

		private static void ClearMenuButton(object obj)
		{
			_menuButtonPointerExitMethod?.Invoke(obj, new object[1]);
			_menuButtonHoveringField?.SetValue(obj, false);
			_menuButtonHoverTimerField?.SetValue(obj, 0f);
			_menuButtonClickedField?.SetValue(obj, false);
			_menuButtonClickTimerField?.SetValue(obj, 0f);
			_menuButtonStateField?.SetValue(obj, 2);
		}

		private static void ClearMenuElementHover(object obj)
		{
			_menuElementIsHoveringField?.SetValue(obj, false);
		}

		private static void ClearMenuSlider(object obj)
		{
			_menuSliderHoveringField?.SetValue(obj, false);
		}

		private static void ClearMenuSelectionBox(object obj)
		{
			_selectionBoxActiveTargetTimerField?.SetValue(obj, 0f);
			_selectionBoxClickTimerField?.SetValue(obj, 0f);
		}
	}
}