Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ValheimCursorLockFix v1.0.2
plugins\ValheimCursorLockFix.dll
Decompiled 13 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; 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(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ValheimCursorLockFix")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ValheimCursorLockFix")] [assembly: AssemblyTitle("ValheimCursorLockFix")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 ValheimCursorLockFix { [BepInPlugin("ua.gyrocopter.valheim.cursorlockfix", "ValheimCursorLockFix", "1.0.2")] public sealed class ValheimCursorLockFixPlugin : BaseUnityPlugin { public const string PluginGuid = "ua.gyrocopter.valheim.cursorlockfix"; public const string PluginName = "ValheimCursorLockFix"; public const string PluginVersion = "1.0.2"; private ConfigEntry<bool> _enableFix; private ConfigEntry<bool> _forceLockInGameplay; private ConfigEntry<bool> _unlockInMenus; private ConfigEntry<KeyboardShortcut> _toggleKey; private ConfigEntry<bool> _debugLogging; private bool _lastShouldLock; private bool _hasAppliedCursorState; private string _lastReason; private static readonly Dictionary<string, Type> TypeCache = new Dictionary<string, Type>(); private void Awake() { //IL_007e: Unknown result type (might be due to invalid IL or missing references) _enableFix = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableFix", true, "Enable or disable the cursor lock fix."); _forceLockInGameplay = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceLockInGameplay", true, "Force Unity cursor lock while gameplay is active."); _unlockInMenus = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UnlockInMenus", true, "Force cursor unlock while menus, inventory, chat, console, build menu, map, or text input are active."); _toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Keyboard shortcut that toggles EnableFix during play."); _debugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Enable verbose debug logging."); DebugLog("Plugin loaded."); } private void Update() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = _toggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { _enableFix.Value = !_enableFix.Value; ((BaseUnityPlugin)this).Config.Save(); DebugLog("EnableFix toggled to " + _enableFix.Value + "."); if (!_enableFix.Value) { ApplyUnlock("fix disabled"); } } if (!_enableFix.Value) { return; } if (ShouldLockCursor(out var reason)) { if (_forceLockInGameplay.Value) { ApplyLock(reason); } } else if (_unlockInMenus.Value) { ApplyUnlock(reason); } } private bool ShouldLockCursor(out string reason) { if (!Application.isFocused) { reason = "application not focused"; return false; } if (!HasZInputInstance()) { reason = "ZInput unavailable"; return false; } if (!HasLocalPlayer()) { reason = "local player unavailable"; return false; } if (IsMenuVisibleSafe()) { reason = "menu visible"; return false; } if (IsInventoryVisibleSafe()) { reason = "inventory visible"; return false; } if (IsBuildMenuVisibleSafe()) { reason = "build menu visible"; return false; } if (IsMapVisibleSafe()) { reason = "map visible"; return false; } if (IsStoreVisibleSafe()) { reason = "store visible"; return false; } if (IsTextViewerVisibleSafe()) { reason = "text viewer visible"; return false; } if (IsTextInputVisibleSafe()) { reason = "text input visible"; return false; } if (IsChatFocusedSafe()) { reason = "chat focused"; return false; } if (IsConsoleVisibleSafe()) { reason = "console visible"; return false; } reason = "gameplay"; return true; } private void ApplyLock(string reason) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Cursor.lockState != 1) { Cursor.lockState = (CursorLockMode)1; } if (Cursor.visible) { Cursor.visible = false; } LogCursorStateChanged(shouldLock: true, reason); } private void ApplyUnlock(string reason) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if ((int)Cursor.lockState != 0) { Cursor.lockState = (CursorLockMode)0; } if (!Cursor.visible) { Cursor.visible = true; } LogCursorStateChanged(shouldLock: false, reason); } private void LogCursorStateChanged(bool shouldLock, string reason) { if (!_hasAppliedCursorState || _lastShouldLock != shouldLock || !string.Equals(_lastReason, reason, StringComparison.Ordinal)) { _hasAppliedCursorState = true; _lastShouldLock = shouldLock; _lastReason = reason; DebugLog((shouldLock ? "Locked" : "Unlocked") + " cursor: " + reason + "."); } } private bool HasZInputInstance() { return GetStaticMemberValue(FindType("ZInput"), "instance") != null; } private bool HasLocalPlayer() { return GetStaticMemberValue(FindType("Player"), "m_localPlayer") != null; } private bool IsMenuVisibleSafe() { return InvokeStaticBool(FindType("Menu"), "IsVisible"); } private bool IsInventoryVisibleSafe() { return InvokeInstanceBool(GetStaticMemberValue(FindType("InventoryGui"), "instance"), "IsVisible"); } private bool IsTextInputVisibleSafe() { return InvokeStaticBool(FindType("TextInput"), "IsVisible"); } private bool IsBuildMenuVisibleSafe() { object staticMemberValue = GetStaticMemberValue(FindType("Hud"), "instance"); if (InvokeInstanceBool(staticMemberValue, "IsPieceSelectionVisible") || InvokeInstanceBool(staticMemberValue, "IsBuildMenuVisible") || InvokeInstanceBool(staticMemberValue, "IsBuildSelectionVisible")) { return true; } return IsAnyInstanceMemberActive(staticMemberValue, "m_pieceSelectionWindow", "m_pieceSelection", "m_buildSelection", "m_buildMenu", "m_pieceListRoot"); } private bool IsMapVisibleSafe() { object staticMemberValue = GetStaticMemberValue(FindType("Minimap"), "instance"); if (!InvokeInstanceBool(staticMemberValue, "IsOpen") && !InvokeInstanceBool(staticMemberValue, "IsVisible")) { return IsAnyInstanceMemberActive(staticMemberValue, "m_largeRoot", "m_mapRoot"); } return true; } private bool IsStoreVisibleSafe() { object staticMemberValue = GetStaticMemberValue(FindType("StoreGui"), "instance"); if (!InvokeInstanceBool(staticMemberValue, "IsVisible")) { return IsAnyInstanceMemberActive(staticMemberValue, "m_rootPanel", "m_panel"); } return true; } private bool IsTextViewerVisibleSafe() { object staticMemberValue = GetStaticMemberValue(FindType("TextViewer"), "instance"); if (!InvokeInstanceBool(staticMemberValue, "IsVisible")) { return IsAnyInstanceMemberActive(staticMemberValue, "m_root", "m_texts"); } return true; } private bool IsChatFocusedSafe() { return InvokeInstanceBool(GetStaticMemberValue(FindType("Chat"), "instance"), "HasFocus"); } private bool IsConsoleVisibleSafe() { return InvokeStaticBool(FindType("Console"), "IsVisible"); } private static Type FindType(string typeName) { if (TypeCache.TryGetValue(typeName, out var value)) { return value; } Type type = Type.GetType(typeName); if (type != null) { TypeCache[typeName] = type; return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type2 = assemblies[i].GetType(typeName); if (type2 != null) { TypeCache[typeName] = type2; return type2; } } TypeCache[typeName] = null; return null; } private static object GetStaticMemberValue(Type type, string memberName) { if (type == null) { return null; } try { FieldInfo field = type.GetField(memberName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(null); } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); return (property != null) ? property.GetValue(null, null) : null; } catch { return null; } } private static object GetInstanceMemberValue(object instance, string memberName) { if (instance == null) { return null; } try { Type type = instance.GetType(); FieldInfo field = type.GetField(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(instance); } PropertyInfo property = type.GetProperty(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); return (property != null) ? property.GetValue(instance, null) : null; } catch { return null; } } private static bool IsAnyInstanceMemberActive(object instance, params string[] memberNames) { if (instance == null || memberNames == null) { return false; } for (int i = 0; i < memberNames.Length; i++) { if (IsUnityObjectActive(GetInstanceMemberValue(instance, memberNames[i]))) { return true; } } return false; } private static bool IsUnityObjectActive(object value) { if (value == null) { return false; } if (TryGetBoolProperty(value, "activeInHierarchy", out var result) || TryGetBoolProperty(value, "activeSelf", out result) || TryGetNestedGameObjectActive(value, out result)) { return result; } return false; } private static bool TryGetNestedGameObjectActive(object value, out bool active) { active = false; try { PropertyInfo property = value.GetType().GetProperty("gameObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); object value2 = ((property != null) ? property.GetValue(value, null) : null); return TryGetBoolProperty(value2, "activeInHierarchy", out active) || TryGetBoolProperty(value2, "activeSelf", out active); } catch { return false; } } private static bool TryGetBoolProperty(object value, string propertyName, out bool result) { result = false; if (value == null) { return false; } try { PropertyInfo property = value.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || property.PropertyType != typeof(bool)) { return false; } result = (bool)property.GetValue(value, null); return true; } catch { return false; } } private static bool InvokeStaticBool(Type type, string methodName) { if (type == null) { return false; } MethodInfo method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(bool)) { return false; } try { return (bool)method.Invoke(null, null); } catch { return false; } } private static bool InvokeInstanceBool(object instance, string methodName) { if (instance == null) { return false; } MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(bool)) { return false; } try { return (bool)method.Invoke(instance, null); } catch { return false; } } private void DebugLog(string message) { if (_debugLogging != null && _debugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } } } }