mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-17 16:47:52 +08:00
2.0.0
lots, see release description
This commit is contained in:
186
src/UI/ForceUnlockCursor.cs
Normal file
186
src/UI/ForceUnlockCursor.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if ML
|
||||
using Harmony;
|
||||
#else
|
||||
using HarmonyLib;
|
||||
#endif
|
||||
|
||||
namespace Explorer.UI
|
||||
{
|
||||
public class ForceUnlockCursor
|
||||
{
|
||||
public static bool Unlock
|
||||
{
|
||||
get => m_forceUnlock;
|
||||
set => SetForceUnlock(value);
|
||||
}
|
||||
private static bool m_forceUnlock;
|
||||
|
||||
private static CursorLockMode m_lastLockMode;
|
||||
private static bool m_lastVisibleState;
|
||||
private static bool m_currentlySettingCursor = false;
|
||||
|
||||
public static bool ShouldForceMouse => ExplorerCore.ShowMenu && Unlock;
|
||||
|
||||
private static Type CursorType => m_cursorType ?? (m_cursorType = ReflectionHelpers.GetTypeByName("UnityEngine.Cursor"));
|
||||
private static Type m_cursorType;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Check if Cursor class is loaded
|
||||
if (CursorType == null)
|
||||
{
|
||||
ExplorerCore.Log("Trying to manually load Cursor module...");
|
||||
|
||||
if (ReflectionHelpers.LoadModule("UnityEngine.CoreModule") && CursorType != null)
|
||||
{
|
||||
ExplorerCore.Log("Ok!");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Could not load UnityEngine.Cursor module!");
|
||||
}
|
||||
}
|
||||
|
||||
// Get current cursor state and enable cursor
|
||||
m_lastLockMode = Cursor.lockState;
|
||||
m_lastVisibleState = Cursor.visible;
|
||||
|
||||
// Setup Harmony Patches
|
||||
TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_lockState))), true);
|
||||
TryPatch("lockState", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_lockState))), false);
|
||||
|
||||
TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Prefix_set_visible))), true);
|
||||
TryPatch("visible", new HarmonyMethod(typeof(ForceUnlockCursor).GetMethod(nameof(Postfix_get_visible))), false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"Exception on CursorControl.Init! {e.GetType()}, {e.Message}");
|
||||
}
|
||||
|
||||
Unlock = true;
|
||||
}
|
||||
|
||||
private static void TryPatch(string property, HarmonyMethod patch, bool setter)
|
||||
{
|
||||
try
|
||||
{
|
||||
var harmony =
|
||||
#if ML
|
||||
ExplorerMelonMod.Instance.harmonyInstance;
|
||||
#else
|
||||
ExplorerBepInPlugin.HarmonyInstance;
|
||||
#endif
|
||||
;
|
||||
|
||||
var prop = typeof(Cursor).GetProperty(property);
|
||||
|
||||
if (setter)
|
||||
{
|
||||
// setter is prefix
|
||||
harmony.Patch(prop.GetSetMethod(), prefix: patch);
|
||||
}
|
||||
else
|
||||
{
|
||||
// getter is postfix
|
||||
harmony.Patch(prop.GetGetMethod(), postfix: patch);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"[NON-FATAL] Couldn't patch a method: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetForceUnlock(bool unlock)
|
||||
{
|
||||
m_forceUnlock = unlock;
|
||||
UpdateCursorControl();
|
||||
}
|
||||
|
||||
public static void Update()
|
||||
{
|
||||
// Check Force-Unlock input
|
||||
if (InputManager.GetKeyDown(KeyCode.LeftAlt))
|
||||
{
|
||||
Unlock = !Unlock;
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateCursorControl()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_currentlySettingCursor = true;
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor.lockState = m_lastLockMode;
|
||||
Cursor.visible = m_lastVisibleState;
|
||||
}
|
||||
m_currentlySettingCursor = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ExplorerCore.Log($"Exception setting Cursor state: {e.GetType()}, {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Force mouse to stay unlocked and visible while UnlockMouse and ShowMenu are true.
|
||||
// Also keep track of when anything else tries to set Cursor state, this will be the
|
||||
// value that we set back to when we close the menu or disable force-unlock.
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_lockState(ref CursorLockMode value)
|
||||
{
|
||||
if (!m_currentlySettingCursor)
|
||||
{
|
||||
m_lastLockMode = value;
|
||||
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
value = CursorLockMode.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Prefix_set_visible(ref bool value)
|
||||
{
|
||||
if (!m_currentlySettingCursor)
|
||||
{
|
||||
m_lastVisibleState = value;
|
||||
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Postfix_get_lockState(ref CursorLockMode __result)
|
||||
{
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
__result = m_lastLockMode;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
public static void Postfix_get_visible(ref bool __result)
|
||||
{
|
||||
if (ShouldForceMouse)
|
||||
{
|
||||
__result = m_lastVisibleState;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user