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 FOff v0.3.0
FOff.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("FOff")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("0.3.0.0")] [assembly: AssemblyInformationalVersion("0.3.0+4357acda50447985cb03fdb3fe2e2a87952d7684")] [assembly: AssemblyProduct("FOff")] [assembly: AssemblyTitle("FOff")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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 FOff { [BepInPlugin("com.Jello.Foff", "F Off", "0.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class FOffPlugin : BaseUnityPlugin { public const string PluginGuid = "com.Jello.Foff"; public const string PluginName = "F Off"; public const string PluginVersion = "0.3.0"; public const string ConfigurationManagerGuid = "com.bepis.bepinex.configurationmanager"; internal static ConfigEntry<KeyboardShortcut> FilterKey; internal static ConfigEntry<KeyboardShortcut> PreviousTabKey; internal static ConfigEntry<KeyboardShortcut> NextTabKey; internal static ManualLogSource Log; private Harmony? _harmony; private static bool _uiReflectionInitialized; private static bool _uiReflectionAvailable; private static bool _uiFailureLogged; private static Type? _textMeshProType; private static FieldInfo? _mouseKeyboardHintField; private static PropertyInfo? _tmpTextProperty; private void Awake() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Expected O, but got Unknown //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; PreviousTabKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Build Menu", "Previous Tab Key", new KeyboardShortcut((KeyCode)113, Array.Empty<KeyCode>()), new ConfigDescription("Key used to move to the previous tab in Valheim's build menu.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 3 } })); NextTabKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Build Menu", "Next Tab Key", new KeyboardShortcut((KeyCode)101, Array.Empty<KeyCode>()), new ConfigDescription("Key used to move to the next tab in Valheim's build menu.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 2 } })); FilterKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Build Menu", "Filter Key", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), new ConfigDescription("Key used to focus the Filter field in Valheim's build menu.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Order = 1 } })); FilterKey.SettingChanged += OnFilterKeyChanged; PreviousTabKey.SettingChanged += OnTabKeyChanged; NextTabKey.SettingChanged += OnTabKeyChanged; _harmony = new Harmony("com.Jello.Foff"); _harmony.PatchAll(typeof(FOffPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)("F Off 0.3.0 loaded. " + $"Filter: {FilterKey.Value}, " + $"Previous Tab: {PreviousTabKey.Value}, " + $"Next Tab: {NextTabKey.Value}")); } private void OnDestroy() { if (FilterKey != null) { FilterKey.SettingChanged -= OnFilterKeyChanged; } if (PreviousTabKey != null) { PreviousTabKey.SettingChanged -= OnTabKeyChanged; } if (NextTabKey != null) { NextTabKey.SettingChanged -= OnTabKeyChanged; } Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private static void OnFilterKeyChanged(object sender, EventArgs args) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"Filter key changed to: {FilterKey.Value}"); } RefreshVisibleFilterHints(); } private static void OnTabKeyChanged(object sender, EventArgs args) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("Build tab keys changed. " + $"Previous: {PreviousTabKey.Value}, " + $"Next: {NextTabKey.Value}")); } RefreshVisibleTabHints(); } internal static bool IsFilterKeyPressed() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (FilterKey == null) { return false; } KeyboardShortcut value = FilterKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey == 0) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { if (!ZInput.GetKey(modifier, true)) { return false; } } return ZInput.GetKey(((KeyboardShortcut)(ref value)).MainKey, true); } internal static bool IsShortcutDown(KeyboardShortcut shortcut) { return ((KeyboardShortcut)(ref shortcut)).IsDown(); } internal static void UpdateBuildMenuTabKeys(BuildUi buildUi) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)buildUi == (Object)null || (Object)(object)buildUi.m_tabHandler == (Object)null || PreviousTabKey == null || NextTabKey == null) { return; } TabHandler tabHandler = buildUi.m_tabHandler; bool flag = IsShortcutDown(PreviousTabKey.Value); bool flag2 = IsShortcutDown(NextTabKey.Value); int num = 0; if (flag) { num = -1; } else if (flag2) { num = 1; } if (num == 0 || tabHandler.m_tabs.Count == 0) { return; } int activeTab = tabHandler.GetActiveTab(); int num2 = activeTab + num; if (tabHandler.m_cycling) { if (num2 < 0) { num2 = tabHandler.m_tabs.Count - 1; } else if (num2 >= tabHandler.m_tabs.Count) { num2 = 0; } } else { num2 = Math.Max(0, Math.Min(tabHandler.m_tabs.Count - 1, num2)); } int num3 = num2; while (!Object.op_Implicit((Object)(object)tabHandler.m_tabs[num2].m_button)) { num2 += num; if (tabHandler.m_cycling) { if (num2 < 0) { num2 = tabHandler.m_tabs.Count - 1; } else if (num2 >= tabHandler.m_tabs.Count) { num2 = 0; } if (num2 == num3) { return; } continue; } return; } tabHandler.SetActiveTabViaButtonIfAvailable(num2); } private static bool EnsureUiReflection() { if (_uiReflectionInitialized) { return _uiReflectionAvailable; } _uiReflectionInitialized = true; try { _textMeshProType = AccessTools.TypeByName("TMPro.TextMeshProUGUI"); if (_textMeshProType == null) { LogUiWarningOnce("Could not resolve TextMeshPro. Keybinds will still work."); return false; } _mouseKeyboardHintField = AccessTools.Field(typeof(UIInputHint), "m_mouseKeyboardHint"); _tmpTextProperty = AccessTools.Property(_textMeshProType, "text"); if (_mouseKeyboardHintField == null || _tmpTextProperty == null || !_tmpTextProperty.CanWrite) { LogUiWarningOnce("Valheim's key hint UI no longer matches the expected layout. Keybinds will still work."); return false; } _uiReflectionAvailable = true; return true; } catch (Exception ex) { LogUiWarningOnce("Could not initialize key hint support: " + ex.Message); return false; } } internal static void UpdateFilterHint(UIInputHint inputHint) { if (!EnsureUiReflection()) { return; } try { GameObject gameObject = ((Component)inputHint).gameObject; if (((Object)gameObject).name != "SearchBarHint") { return; } Transform parent = gameObject.transform.parent; if ((Object)(object)parent == (Object)null || ((Object)parent).name != "SearchBar") { return; } object? value = _mouseKeyboardHintField.GetValue(inputHint); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val == (Object)null) { return; } Transform val2 = val.transform.Find("Text"); if (!((Object)(object)val2 == (Object)null)) { Component component = ((Component)val2).GetComponent(_textMeshProType); if (!((Object)(object)component == (Object)null)) { _tmpTextProperty.SetValue(component, GetFilterHintText(), null); } } } catch (Exception ex) { LogUiWarningOnce("Could not update Filter key hint: " + ex.Message); } } private static void RefreshVisibleFilterHints() { if (!EnsureUiReflection()) { return; } try { UIInputHint[] array = Object.FindObjectsByType<UIInputHint>((FindObjectsSortMode)0); UIInputHint[] array2 = array; foreach (UIInputHint inputHint in array2) { UpdateFilterHint(inputHint); } } catch (Exception ex) { LogUiWarningOnce("Could not refresh Filter key hint: " + ex.Message); } } internal static void UpdateTabHints(BuildUi buildUi) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)buildUi == (Object)null || PreviousTabKey == null || NextTabKey == null || !EnsureUiReflection()) { return; } try { Transform transform = ((Component)buildUi).transform; Transform val = transform.Find("bar/SelectionWindow/TabContainer/InputHelp/MK hints/Left"); Transform val2 = transform.Find("bar/SelectionWindow/TabContainer/InputHelp/MK hints/Right"); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { SetTabHintText(val, GetShortcutHintText(PreviousTabKey.Value)); SetTabHintText(val2, GetShortcutHintText(NextTabKey.Value)); } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Could not update build tab key hints: " + ex.Message)); } } } private static void RefreshVisibleTabHints() { if (!EnsureUiReflection()) { return; } try { BuildUi[] array = Object.FindObjectsByType<BuildUi>((FindObjectsSortMode)0); BuildUi[] array2 = array; foreach (BuildUi buildUi in array2) { UpdateTabHints(buildUi); } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("Could not refresh build tab key hints: " + ex.Message)); } } } private static void SetTabHintText(Transform hint, string text) { Component componentInChildren = ((Component)hint).GetComponentInChildren(_textMeshProType, true); if (!((Object)(object)componentInChildren == (Object)null)) { _tmpTextProperty.SetValue(componentInChildren, text, null); } } private unsafe static string GetShortcutHintText(KeyboardShortcut shortcut) { //IL_0003: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 KeyCode mainKey = ((KeyboardShortcut)(ref shortcut)).MainKey; if ((int)mainKey == 0) { return string.Empty; } string text = ((object)(*(KeyCode*)(&mainKey))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Alpha", StringComparison.Ordinal) && text.Length == 6) { return text.Substring(5); } return text; } private static string GetFilterHintText() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return GetShortcutHintText(FilterKey.Value); } private static void LogUiWarningOnce(string message) { if (!_uiFailureLogged) { _uiFailureLogged = true; ManualLogSource log = Log; if (log != null) { log.LogWarning((object)message); } } } } [HarmonyPatch(typeof(BuildUi), "Awake")] internal static class BuildUiAwakePatch { private static void Postfix(BuildUi __instance) { if ((Object)(object)__instance.m_tabHandler != (Object)null) { __instance.m_tabHandler.m_keybaordInput = false; ManualLogSource log = FOffPlugin.Log; if (log != null) { log.LogInfo((object)"Disabled vanilla BuildUi Q/E tab handling."); } } FOffPlugin.UpdateTabHints(__instance); } } [HarmonyPatch(typeof(TabHandler), "Update")] internal static class TabHandlerUpdatePatch { private static void Prefix(TabHandler __instance) { if (!((Object)(object)((Component)__instance).GetComponentInParent<BuildUi>() == (Object)null)) { __instance.m_keybaordInput = false; } } } [HarmonyPatch(typeof(BuildUi), "NavigationUpdate")] internal static class BuildUiNavigationUpdatePatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); MethodInfo methodInfo = AccessTools.Method(typeof(ZInput), "GetKey", new Type[2] { typeof(KeyCode), typeof(bool) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(FOffPlugin), "IsFilterKeyPressed", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { ManualLogSource log = FOffPlugin.Log; if (log != null) { log.LogError((object)"Could not resolve Filter patch methods. BuildUi was left untouched."); } return list; } List<int> list2 = new List<int>(); for (int i = 0; i <= list.Count - 3; i++) { if (LoadsFilterKey(list[i]) && LoadsTrue(list[i + 1]) && CallsMethod(list[i + 2], methodInfo)) { list2.Add(i); } } if (list2.Count != 1) { ManualLogSource log2 = FOffPlugin.Log; if (log2 != null) { log2.LogWarning((object)("Expected one hardcoded BuildUi Filter-key " + $"pattern, but found {list2.Count}. " + "Vanilla behavior was preserved.")); } return list; } int num = list2[0]; CodeInstruction val = new CodeInstruction(OpCodes.Call, (object)methodInfo2); for (int j = num; j < num + 3; j++) { val.labels.AddRange(list[j].labels); val.blocks.AddRange(list[j].blocks); } list.RemoveRange(num, 3); list.Insert(num, val); ManualLogSource log3 = FOffPlugin.Log; if (log3 != null) { log3.LogInfo((object)"Replaced the hardcoded F check in BuildUi.NavigationUpdate()."); } return list; } private static void Postfix(BuildUi __instance) { FOffPlugin.UpdateBuildMenuTabKeys(__instance); FOffPlugin.UpdateTabHints(__instance); } private static bool LoadsFilterKey(CodeInstruction instruction) { return instruction.opcode == OpCodes.Ldc_I4_S && instruction.operand is sbyte b && b == 102; } private static bool LoadsTrue(CodeInstruction instruction) { return instruction.opcode == OpCodes.Ldc_I4_1; } private static bool CallsMethod(CodeInstruction instruction, MethodInfo method) { return (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo && methodInfo == method; } } internal sealed class ConfigurationManagerAttributes { public int? Order; } [HarmonyPatch(typeof(UIInputHint), "UpdateInputHints")] internal static class SearchBarInputHintPatch { private static void Postfix(UIInputHint __instance) { FOffPlugin.UpdateFilterHint(__instance); } } }