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 SortingTweaks v1.1.0
SortingTweaks.dll
Decompiled 6 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace SortingTweaks; internal enum SortBy { Default = 0, Id = 1, Name = 2, Weight = 4, Type = 5, Biome = 6 } internal struct SortSetting { public SortBy By; public bool Ascending; } internal static class ContainerSort { private const string QssSortModule = "QuickStackStore.SortModule"; private static ConfigEntry<float> buttonOffsetX; private static ConfigEntry<float> buttonOffsetY; private static readonly Dictionary<string, SortSetting> settings = new Dictionary<string, SortSetting>(); private static string settingsPath; private static SortSetting? activeSetting; private static readonly SortBy[] sortCycle = new SortBy[6] { SortBy.Default, SortBy.Id, SortBy.Name, SortBy.Weight, SortBy.Type, SortBy.Biome }; private static int[] typeToCategory; private static Action<Container> qssSortContainer; private static readonly FieldRef<InventoryGui, Container> currentContainerRef = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static Button byButton; private static Button directionButton; private static TMP_Text byText; private static TMP_Text directionText; private static Container shownContainer; internal static void Init(BaseUnityPlugin plugin, Harmony harmony) { //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_0199: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown Type type = AccessTools.TypeByName("QuickStackStore.SortModule"); if (type == null) { SortingTweaksPlugin.Log.LogError((object)"QuickStackStore.SortModule not found, per-container sort is off."); return; } MethodInfo methodInfo = AccessTools.Method(type, "SortInternal", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "SortCompare", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(type, "SortContainer", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null) { SortingTweaksPlugin.Log.LogError((object)"Quick Stack Store sorting methods not found (incompatible version?), per-container sort is off."); return; } FieldInfo fieldInfo = AccessTools.Field(type, "TypeToCategory"); typeToCategory = ((fieldInfo != null) ? ((int[])fieldInfo.GetValue(null)) : null); qssSortContainer = AccessTools.MethodDelegate<Action<Container>>(methodInfo3, (object)null, true); buttonOffsetX = plugin.Config.Bind<float>("ContainerSort", "ButtonOffsetX", -12f, "Horizontal offset of the per-container sort buttons from the top right corner of the container panel. Negative moves them left."); buttonOffsetY = plugin.Config.Bind<float>("ContainerSort", "ButtonOffsetY", -10f, "Vertical offset of the per-container sort buttons from the top right corner of the container panel. Negative moves them down."); buttonOffsetX.SettingChanged += delegate { LayoutButtons(); }; buttonOffsetY.SettingChanged += delegate { LayoutButtons(); }; settingsPath = Path.Combine(Paths.ConfigPath, "sortingtweaks.valheim.containers.txt"); LoadSettings(); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ContainerSort), "SortInternalPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ContainerSort), "SortInternalFinalizer", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ContainerSort), "SortComparePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(InventoryGui), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ContainerSort), "InventoryGuiUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void SortInternalPrefix(Inventory inventory) { activeSetting = null; InventoryGui instance = InventoryGui.instance; Container val = (((Object)(object)instance != (Object)null) ? currentContainerRef.Invoke(instance) : null); if (!((Object)(object)val == (Object)null) && val.GetInventory() == inventory) { SortSetting setting = GetSetting(val); if (setting.By != SortBy.Default) { activeSetting = setting; } } } private static void SortInternalFinalizer() { activeSetting = null; } private static bool SortComparePrefix(ItemData a, ItemData b, ref int __result) { if (!activeSetting.HasValue) { return true; } SortSetting value = activeSetting.Value; int num = SortKey(a, value.By).CompareTo(SortKey(b, value.By)); if (!value.Ascending) { num *= -1; } if (num == 0) { num = a.m_shared.m_name.CompareTo(b.m_shared.m_name); } if (num == 0) { num = -a.m_quality.CompareTo(b.m_quality); } if (num == 0) { num = -a.m_stack.CompareTo(b.m_stack); } __result = num; return false; } private static IComparable SortKey(ItemData item, SortBy by) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected I4, but got Unknown switch (by) { case SortBy.Name: return Localization.instance.Localize(item.m_shared.m_name); case SortBy.Weight: return item.m_shared.m_weight; case SortBy.Type: { int num = (int)item.m_shared.m_itemType; if (typeToCategory == null || num < 0 || num >= typeToCategory.Length) { return num; } return typeToCategory[num]; } case SortBy.Biome: return ItemBiomes.SortKey(item); default: return item.m_shared.m_name; } } private static string KeyFor(Container container) { //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) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) string text = "world"; try { if ((Object)(object)ZNet.instance != (Object)null) { text = ZNet.instance.GetWorldName(); } } catch (Exception) { } Vector3 position = ((Component)container).transform.position; return string.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2}|{3}", text, Mathf.RoundToInt(position.x * 10f), Mathf.RoundToInt(position.y * 10f), Mathf.RoundToInt(position.z * 10f)); } private static SortSetting GetSetting(Container container) { if (settings.TryGetValue(KeyFor(container), out var value)) { return value; } return new SortSetting { By = SortBy.Default, Ascending = true }; } private static void SetSetting(Container container, SortSetting setting) { string key = KeyFor(container); if (setting.By == SortBy.Default) { settings.Remove(key); } else { settings[key] = setting; } SaveSettings(); } private static void LoadSettings() { settings.Clear(); try { if (!File.Exists(settingsPath)) { return; } string[] array = File.ReadAllLines(settingsPath); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '\t' }); if (array2.Length == 3 && int.TryParse(array2[1], out var result) && Enum.IsDefined(typeof(SortBy), result)) { settings[array2[0]] = new SortSetting { By = (SortBy)result, Ascending = (array2[2] == "1") }; } } } catch (Exception ex) { SortingTweaksPlugin.Log.LogWarning((object)("Could not read " + settingsPath + ": " + ex.Message)); } } private static void SaveSettings() { try { List<string> list = new List<string>(); foreach (KeyValuePair<string, SortSetting> setting in settings) { string[] obj = new string[5] { setting.Key, "\t", null, null, null }; int num = (int)setting.Value.By; obj[2] = num.ToString(); obj[3] = "\t"; obj[4] = (setting.Value.Ascending ? "1" : "0"); list.Add(string.Concat(obj)); } File.WriteAllLines(settingsPath, list.ToArray()); } catch (Exception ex) { SortingTweaksPlugin.Log.LogWarning((object)("Could not write " + settingsPath + ": " + ex.Message)); } } private static void InventoryGuiUpdatePostfix(InventoryGui __instance) { if ((Object)(object)__instance != (Object)(object)InventoryGui.instance) { return; } Container val = currentContainerRef.Invoke(__instance); if ((Object)(object)val == (Object)null || (Object)(object)__instance.m_container == (Object)null) { shownContainer = null; return; } if ((Object)(object)byButton == (Object)null || (Object)(object)directionButton == (Object)null) { CreateButtons(__instance); shownContainer = null; } if ((Object)(object)val != (Object)(object)shownContainer) { shownContainer = val; RefreshLabels(val); } } private static void CreateButtons(InventoryGui gui) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown byButton = CloneButton(gui, "sortingTweaksSortByButton", out byText); directionButton = CloneButton(gui, "sortingTweaksSortDirectionButton", out directionText); ((UnityEvent)byButton.onClick).AddListener(new UnityAction(OnByClicked)); ((UnityEvent)directionButton.onClick).AddListener(new UnityAction(OnDirectionClicked)); LayoutButtons(); } private static Button CloneButton(InventoryGui gui, string name, out TMP_Text label) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown Button val = Object.Instantiate<Button>(gui.m_takeAllButton, (Transform)(object)gui.m_container); ((Object)val).name = name; ((UnityEventBase)val.onClick).RemoveAllListeners(); UIGamePad[] components = ((Component)val).GetComponents<UIGamePad>(); for (int i = 0; i < components.Length; i++) { Object.Destroy((Object)(object)components[i]); } label = null; foreach (Transform item in ((Component)val).transform) { Transform val2 = item; TMP_Text component = ((Component)val2).GetComponent<TMP_Text>(); if ((Object)(object)component != (Object)null && (Object)(object)label == (Object)null) { label = component; component.enableAutoSizing = true; component.fontSizeMin = 10f; component.fontSizeMax = 20f; component.textWrappingMode = (TextWrappingModes)0; } else { ((Component)val2).gameObject.SetActive(false); } } ((Component)val).gameObject.SetActive(true); return val; } private static void LayoutButtons() { if (!((Object)(object)byButton == (Object)null) && !((Object)(object)directionButton == (Object)null)) { PlaceTopRight(directionButton, buttonOffsetX.Value, buttonOffsetY.Value, 62f, 30f); PlaceTopRight(byButton, buttonOffsetX.Value - 62f - 6f, buttonOffsetY.Value, 104f, 30f); } } private static void PlaceTopRight(Button button, float x, float y, float width, float height) { //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) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)((Component)button).transform; val.anchorMin = new Vector2(1f, 1f); val.anchorMax = new Vector2(1f, 1f); val.pivot = new Vector2(1f, 1f); val.sizeDelta = new Vector2(width, height); val.anchoredPosition = new Vector2(x, y); } private static void RefreshLabels(Container container) { SortSetting setting = GetSetting(container); if ((Object)(object)byText != (Object)null) { byText.text = "Sort: " + Label(setting.By); } if ((Object)(object)directionText != (Object)null) { directionText.text = (setting.Ascending ? "Asc" : "Desc"); } if ((Object)(object)directionButton != (Object)null) { ((Selectable)directionButton).interactable = setting.By != SortBy.Default; } } private static string Label(SortBy by) { return by switch { SortBy.Id => "ID", SortBy.Name => "Name", SortBy.Weight => "Weight", SortBy.Type => "Type", SortBy.Biome => "Biome", _ => "Default", }; } private static void OnByClicked() { Container val = shownContainer; if (!((Object)(object)val == (Object)null)) { SortSetting setting = GetSetting(val); setting.By = sortCycle[(Array.IndexOf(sortCycle, setting.By) + 1) % sortCycle.Length]; Apply(val, setting); } } private static void OnDirectionClicked() { Container val = shownContainer; if (!((Object)(object)val == (Object)null)) { SortSetting setting = GetSetting(val); if (setting.By != SortBy.Default) { setting.Ascending = !setting.Ascending; Apply(val, setting); } } } private static void Apply(Container container, SortSetting setting) { SetSetting(container, setting); RefreshLabels(container); if (container.IsOwner()) { qssSortContainer(container); } } } internal enum ComboScore { Sum, Max } internal static class FoodTweaks { private sealed class Row { public Recipe Recipe; public ItemData Item; public GameObject Element; public bool CanCraft; } private const string FoodCategoriesPlugin = "FoodCategories.Plugin"; private const float EyeRowHeight = 25f; private static ConfigEntry<bool> showUncraftable; private static ConfigEntry<ComboScore> comboScore; private static IDictionary bars; private static MethodInfo apply; private static MethodInfo classify; private static Func<ItemData, bool> isFood; private static Func<ItemData, bool> isUnfilteredOnly; private static Func<Recipe, bool, bool> belongsToStation; private static Type filterEnum; private static FieldInfo barCurrent; private static FieldInfo barRoot; private static FieldInfo barPreparationStation; private static FieldInfo barButtons; private static FieldInfo barCraftTabTemplate; private static FieldInfo barUpgradeTabTemplate; private static FieldInfo availableRecipes; private static int filterAll; private static int filterHealth; private static int filterStamina; private static int filterEitr; private static int filterBalanced; private static int filterFeast; private static Type rowType; private static PropertyInfo rowRecipe; private static PropertyInfo rowItem; private static PropertyInfo rowElement; private static PropertyInfo rowCanCraft; private static readonly HashSet<int> selected = new HashSet<int>(); private static readonly HashSet<int> hookedButtons = new HashSet<int>(); private static Button eyeButton; private static Image eyeIcon; private static Sprite eyeOpen; private static Sprite eyeClosed; private static bool warned; internal static void Init(BaseUnityPlugin plugin, Harmony harmony) { //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Expected O, but got Unknown //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Expected O, but got Unknown Type type = AccessTools.TypeByName("FoodCategories.Plugin"); if (type == null) { SortingTweaksPlugin.Log.LogError((object)"FoodCategories.Plugin not found, the food tweaks are off."); return; } filterEnum = type.GetNestedType("FoodFilter", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); Type nestedType = type.GetNestedType("FilterBar", BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo fieldInfo = AccessTools.Field(type, "Bars"); apply = AccessTools.Method(type, "Apply", (Type[])null, (Type[])null); classify = AccessTools.Method(type, "Classify", (Type[])null, (Type[])null); MethodInfo methodInfo = AccessTools.Method(type, "IsFood", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(type, "IsUnfilteredOnly", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(type, "BelongsToStation", (Type[])null, (Type[])null); availableRecipes = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes"); if (nestedType != null) { barCurrent = AccessTools.Field(nestedType, "Current"); barRoot = AccessTools.Field(nestedType, "Root"); barPreparationStation = AccessTools.Field(nestedType, "PreparationStation"); barButtons = AccessTools.Field(nestedType, "Buttons"); barCraftTabTemplate = AccessTools.Field(nestedType, "CraftTabTemplate"); barUpgradeTabTemplate = AccessTools.Field(nestedType, "UpgradeTabTemplate"); } if (new object[15] { filterEnum, nestedType, fieldInfo, apply, classify, methodInfo, methodInfo2, methodInfo3, availableRecipes, barCurrent, barRoot, barPreparationStation, barButtons, barCraftTabTemplate, barUpgradeTabTemplate }.Any((object x) => x == null)) { SortingTweaksPlugin.Log.LogError((object)"Food Categories looks different than expected (incompatible version?), the food tweaks are off."); return; } bars = fieldInfo.GetValue(null) as IDictionary; if (bars == null) { SortingTweaksPlugin.Log.LogError((object)"Food Categories filter bars not found, the food tweaks are off."); return; } isFood = AccessTools.MethodDelegate<Func<ItemData, bool>>(methodInfo, (object)null, true); isUnfilteredOnly = AccessTools.MethodDelegate<Func<ItemData, bool>>(methodInfo2, (object)null, true); belongsToStation = AccessTools.MethodDelegate<Func<Recipe, bool, bool>>(methodInfo3, (object)null, true); filterAll = FilterValue("All"); filterHealth = FilterValue("Health"); filterStamina = FilterValue("Stamina"); filterEitr = FilterValue("Eitr"); filterBalanced = FilterValue("Balanced"); filterFeast = FilterValue("Feast"); showUncraftable = plugin.Config.Bind<bool>("Food", "ShowUncraftable", false, "Also list food recipes you know but cannot craft right now (the greyed out ones). Toggled by the eye button next to the food filters."); comboScore = plugin.Config.Bind<ComboScore>("Food", "ComboScore", ComboScore.Sum, "How an Eitr + Health or Eitr + Stamina combination is ranked. Sum adds both values, Max takes the higher one."); harmony.Patch((MethodBase)apply, (HarmonyMethod)null, new HarmonyMethod(typeof(FoodTweaks), "ApplyPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo4 = AccessTools.Method(type, "IsFoodStation", (Type[])null, (Type[])null); if (methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(FoodTweaks), "SkipMeadStation", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static bool SkipMeadStation(ref bool __result, ref bool preparationStation) { CraftingStation val = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetCurrentCraftingStation() : null); if ((Object)(object)val == (Object)null || ((Object)((Component)val).gameObject).name.IndexOf("mead", StringComparison.OrdinalIgnoreCase) < 0) { return true; } preparationStation = false; __result = false; return false; } private static int FilterValue(string name) { return (int)Enum.Parse(filterEnum, name); } private static void ApplyPostfix(InventoryGui gui) { try { Refresh(gui); } catch (Exception ex) { if (!warned) { warned = true; SortingTweaksPlugin.Log.LogWarning((object)("Food tweaks failed: " + ex)); } } } private static void Refresh(InventoryGui gui) { if ((Object)(object)gui == (Object)null || !gui.InCraftTab() || !bars.Contains(gui)) { return; } object obj = bars[gui]; object? value = barRoot.GetValue(obj); RectTransform val = (RectTransform)((value is RectTransform) ? value : null); if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf && !InventoryGui.IsVisible()) { ((Component)val).gameObject.SetActive(false); } else if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeSelf) { IDictionary buttons = (IDictionary)barButtons.GetValue(obj); selected.RemoveWhere((int f) => !buttons.Contains(Enum.ToObject(filterEnum, f))); SyncCurrent(obj); HookButtons(gui, obj, buttons); EnsureEye(obj, val, buttons); StyleButtons(obj, buttons); Relayout(gui, (bool)barPreparationStation.GetValue(obj)); } } private static bool IsCombo(out bool usesHealth) { usesHealth = selected.Contains(filterHealth); if (selected.Contains(filterEitr)) { if (!usesHealth) { return selected.Contains(filterStamina); } return true; } return false; } private static void OnFilterClicked(InventoryGui gui, object bar, int filter) { if (selected.Contains(filter)) { selected.Remove(filter); } else { if (filter == filterBalanced || filter == filterFeast) { selected.Clear(); } else { selected.Remove(filterBalanced); selected.Remove(filterFeast); if (filter == filterHealth) { selected.Remove(filterStamina); } else if (filter == filterStamina) { selected.Remove(filterHealth); } } selected.Add(filter); } SyncCurrent(bar); Reapply(gui); } private static void SyncCurrent(object bar) { int value = filterAll; if (selected.Count > 0) { value = (selected.Contains(filterEitr) ? filterEitr : selected.First()); } barCurrent.SetValue(bar, Enum.ToObject(filterEnum, value)); } private static void Reapply(InventoryGui gui) { if ((Object)(object)gui != (Object)null) { apply.Invoke(null, new object[2] { gui, true }); } } private static void Relayout(InventoryGui gui, bool preparationStation) { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) bool flag = selected.Count > 0; if (!flag && showUncraftable.Value) { return; } List<Row> list = ReadRows(gui); Func<Row, bool> predicate = (Row r) => showUncraftable.Value || r.CanCraft; List<Row> list2 = (flag ? (from r in (from r in list where isFood(r.Item) && belongsToStation(r.Recipe, preparationStation) && !isUnfilteredOnly(r.Item) where Matches(r.Item) select r).Where(predicate) orderby Score(r.Item) descending select r).ToList() : list.Where((Row r) => isFood(r.Item) && belongsToStation(r.Recipe, preparationStation)).Concat(list.Where((Row r) => !isFood(r.Item))).Where(predicate) .ToList()); HashSet<Row> hashSet = new HashSet<Row>(list2); foreach (Row item in list) { item.Element.SetActive(hashSet.Contains(item)); } float recipeListSpace = gui.m_recipeListSpace; for (int num = 0; num < list2.Count; num++) { RectTransform component = list2[num].Element.GetComponent<RectTransform>(); component.anchoredPosition = new Vector2(component.anchoredPosition.x, (float)(-num) * recipeListSpace); } gui.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max((float)list2.Count * recipeListSpace, 30f)); } private static List<Row> ReadRows(InventoryGui gui) { List<Row> list = new List<Row>(); if (!(availableRecipes.GetValue(gui) is IEnumerable enumerable)) { return list; } foreach (object item in enumerable) { if (item != null) { Type type = item.GetType(); if (type != rowType) { rowType = type; rowRecipe = AccessTools.Property(type, "Recipe"); rowItem = AccessTools.Property(type, "ItemData"); rowElement = AccessTools.Property(type, "InterfaceElement"); rowCanCraft = AccessTools.Property(type, "CanCraft"); } object? obj = rowRecipe?.GetValue(item, null); Recipe val = (Recipe)((obj is Recipe) ? obj : null); object? obj2 = rowItem?.GetValue(item, null); ItemData val2 = (ItemData)(((obj2 is ItemData) ? obj2 : null) ?? val?.m_item?.m_itemData); object? obj3 = rowElement?.GetValue(item, null); GameObject val3 = (GameObject)((obj3 is GameObject) ? obj3 : null); if (!((Object)(object)val == (Object)null) && val2 != null && !((Object)(object)val3 == (Object)null)) { list.Add(new Row { Recipe = val, Item = val2, Element = val3, CanCraft = (rowCanCraft != null && (bool)rowCanCraft.GetValue(item, null)) }); } } } return list; } private static bool Matches(ItemData item) { if (IsCombo(out var usesHealth)) { if (item.m_shared.m_foodEitr > 0f) { return PairedValue(item, usesHealth) > 0f; } return false; } int num = selected.First(); return Convert.ToInt32(classify.Invoke(null, new object[1] { item })) == num; } private static float Score(ItemData item) { SharedData shared = item.m_shared; if (IsCombo(out var usesHealth)) { float num = PairedValue(item, usesHealth); if (comboScore.Value != ComboScore.Max) { return shared.m_foodEitr + num; } return Mathf.Max(shared.m_foodEitr, num); } int num2 = selected.First(); if (num2 == filterHealth) { return shared.m_food; } if (num2 == filterStamina) { return shared.m_foodStamina; } if (num2 == filterEitr) { return shared.m_foodEitr; } if (num2 == filterBalanced) { return shared.m_food + shared.m_foodStamina; } return 1f; } private static float PairedValue(ItemData item, bool usesHealth) { if (!usesHealth) { return item.m_shared.m_foodStamina; } return item.m_shared.m_food; } private static void HookButtons(InventoryGui gui, object bar, IDictionary buttons) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown foreach (DictionaryEntry button in buttons) { object? value = button.Value; Button val = (Button)((value is Button) ? value : null); if (!((Object)(object)val == (Object)null) && hookedButtons.Add(((Object)val).GetInstanceID())) { int filter = Convert.ToInt32(button.Key); ((UnityEventBase)val.onClick).RemoveAllListeners(); ((UnityEvent)val.onClick).AddListener((UnityAction)delegate { OnFilterClicked(gui, bar, filter); }); } } } private static void StyleButtons(object bar, IDictionary buttons) { object? value = barCraftTabTemplate.GetValue(bar); Image craftTemplate = (Image)((value is Image) ? value : null); object? value2 = barUpgradeTabTemplate.GetValue(bar); Image upgradeTemplate = (Image)((value2 is Image) ? value2 : null); foreach (DictionaryEntry button in buttons) { object? value3 = button.Value; Button val = (Button)((value3 is Button) ? value3 : null); if ((Object)(object)val != (Object)null) { StyleButton(val, selected.Contains(Convert.ToInt32(button.Key)), craftTemplate, upgradeTemplate); } } if ((Object)(object)eyeButton != (Object)null) { StyleButton(eyeButton, showUncraftable.Value, craftTemplate, upgradeTemplate); if ((Object)(object)eyeIcon != (Object)null) { eyeIcon.sprite = (showUncraftable.Value ? EyeSprite(slashed: false) : EyeSprite(slashed: true)); } } } private static void StyleButton(Button button, bool isSelected, Image craftTemplate, Image upgradeTemplate) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) Image component = ((Component)button).GetComponent<Image>(); Image val = (isSelected ? craftTemplate : upgradeTemplate); if ((Object)(object)component != (Object)null && (Object)(object)val != (Object)null) { component.sprite = val.sprite; component.type = val.type; ((Graphic)component).color = ((Graphic)val).color; ((Graphic)component).material = ((Graphic)val).material; component.preserveAspect = val.preserveAspect; component.fillCenter = val.fillCenter; } Outline obj = ((Component)button).GetComponent<Outline>() ?? ((Component)button).gameObject.AddComponent<Outline>(); ((Behaviour)obj).enabled = isSelected; ((Shadow)obj).effectColor = new Color(1f, 0.42f, 0.06f, 1f); ((Shadow)obj).effectDistance = new Vector2(3f, -3f); Transform val2 = ((Component)button).transform.Find("Valheim Food Icon"); Image val3 = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Image>() : null); if ((Object)(object)val3 != (Object)null) { ((Graphic)val3).rectTransform.sizeDelta = (isSelected ? new Vector2(21f, 21f) : new Vector2(17f, 17f)); } } private static void EnsureEye(object bar, RectTransform root, IDictionary buttons) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)eyeButton != (Object)null && (Object)(object)((Component)eyeButton).transform.parent == (Object)(object)root) { return; } Button val = null; foreach (DictionaryEntry button in buttons) { object? value = button.Value; val = (Button)((value is Button) ? value : null); if ((Object)(object)val != (Object)null) { break; } } if (!((Object)(object)val == (Object)null)) { GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)root, false); ((Object)obj).name = "Sorting Tweaks Eye"; eyeButton = obj.GetComponent<Button>(); ((UnityEventBase)eyeButton.onClick).RemoveAllListeners(); ((UnityEvent)eyeButton.onClick).AddListener(new UnityAction(OnEyeClicked)); Transform val2 = obj.transform.Find("Valheim Food Icon"); eyeIcon = (((Object)(object)val2 != (Object)null) ? ((Component)val2).GetComponent<Image>() : null); if ((Object)(object)eyeIcon != (Object)null) { ((Graphic)eyeIcon).color = new Color(0.95f, 0.92f, 0.85f, 1f); } root.sizeDelta += new Vector2(0f, 25f); } } private static void OnEyeClicked() { showUncraftable.Value = !showUncraftable.Value; Reapply(InventoryGui.instance); } private static Sprite EyeSprite(bool slashed) { if (slashed) { return eyeClosed ?? (eyeClosed = BuildEye(slashed: true)); } return eyeOpen ?? (eyeOpen = BuildEye(slashed: false)); } private static Sprite BuildEye(bool slashed) { //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) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = ((float)j + 0.5f) / 64f * 2f - 1f; float num2 = ((float)i + 0.5f) / 64f * 2f - 1f; float num3 = 0.6f * (1f - num * num); bool flag = Mathf.Abs(num) <= 0.97f && Mathf.Abs(num2) <= num3; bool num4 = Mathf.Abs(num) <= 0.99f && Mathf.Abs(Mathf.Abs(num2) - num3) < 0.09f; bool flag2 = flag && num * num + num2 * num2 < 0.1f; bool flag3 = num4 || flag2; if (slashed) { float num5 = Mathf.Abs(num + num2); bool flag4 = num5 < 0.1f && Mathf.Abs(num) < 0.82f; bool flag5 = num5 < 0.22f && Mathf.Abs(num) < 0.9f; flag3 = flag4 || (flag3 && !flag5); } array[i * 64 + j] = (flag3 ? new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue) : new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, (byte)0)); } } val.SetPixels32(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f); } } internal static class ItemBiomes { private sealed class Source { public string[] Inputs; public bool AnyInput; } internal const int Unknown = 99; private const int Meadows = 0; private const int BlackForest = 1; private const int Swamp = 2; private const int Mountain = 3; private const int Plains = 4; private const int Mistlands = 5; private const int Ashlands = 6; private const int DeepNorth = 7; private const int Ocean = 8; private const int Everywhere = 9; private static readonly Dictionary<string, int> order = new Dictionary<string, int>(); private static readonly Dictionary<string, int> raw = BuildRaw(); private static readonly Dictionary<string, List<Source>> sources = new Dictionary<string, List<Source>>(); private static readonly Dictionary<string, int> resolved = new Dictionary<string, int>(); private static bool built; private static Dictionary<string, int> BuildRaw() { Dictionary<string, int> map = new Dictionary<string, int>(); Action<int, string[]> action = delegate(int biome, string[] prefabs) { foreach (string key in prefabs) { if (!map.ContainsKey(key)) { map[key] = biome; order[key] = order.Count; } } }; action(0, new string[15] { "Flint", "Raspberry", "Mushroom", "Honey", "Dandelion", "QueenBee", "LeatherScraps", "DeerHide", "DeerMeat", "RawMeat", "NeckTail", "HardAntler", "Acorn", "BeechSeeds", "BirchSeeds" }); action(1, new string[19] { "Resin", "Blueberries", "Carrot", "CarrotSeeds", "Thistle", "CopperOre", "TinOre", "TrollHide", "BjornHide", "BjornPaw", "BjornMeat", "GreydwarfEye", "AncientSeed", "BoneFragments", "SurtlingCore", "MushroomYellow", "CryptKey", "FirCone", "PineCone" }); action(2, new string[12] { "Ooze", "Bloodbag", "Entrails", "Chain", "IronScrap", "Guck", "WitheredBone", "Turnip", "TurnipSeeds", "ElderBark", "Root", "Wishbone" }); action(3, new string[12] { "Obsidian", "FreezeGland", "WolfPelt", "WolfFang", "WolfMeat", "DragonTear", "DragonEgg", "SilverOre", "Crystal", "Onion", "OnionSeeds", "JuteRed" }); action(4, new string[10] { "Cloudberry", "Barley", "Flax", "BlackMetalScrap", "LoxMeat", "LoxPelt", "Needle", "Tar", "GoblinTotem", "YagluthDrop" }); action(5, new string[19] { "Carapace", "Mandible", "BugMeat", "Softtissue", "Sap", "YggdrasilWood", "BlackCore", "BlackMarble", "JuteBlue", "RoyalJelly", "MushroomJotunPuffs", "MushroomMagecap", "HareMeat", "ScaleHide", "Bilebag", "CopperScrap", "QueenDrop", "SeekerAspic", "DvergrKey" }); action(6, new string[17] { "FlametalOre", "FlametalOreNew", "AskHide", "AskBladder", "AsksvinMeat", "VoltureMeat", "VoltureEgg", "MorgenHeart", "MorgenSinew", "BoneMawSerpentMeat", "CelestialFeather", "FaderDrop", "Grausten", "Fiddleheadfern", "MushroomSmokePuff", "Vineberry", "AsksvinEgg" }); action(7, new string[18] { "MooseHide", "MooseMeat", "MooseSinew", "SealBlubber", "SealHide", "ElakingHairBundle", "FrostCore", "BarkaBranch", "MoleClaws", "NornThread", "MemorialCoal", "Ice", "KaleSeeds", "Kale", "OatSeeds", "PoteitrSeeds", "Poteitr", "Lingonberry" }); action(0, new string[2] { "Fish1", "Fish2" }); action(1, new string[1] { "Fish5" }); action(2, new string[1] { "Fish6" }); action(3, new string[1] { "Fish4_cave" }); action(4, new string[1] { "Fish7" }); action(5, new string[2] { "Fish9", "Fish12" }); action(6, new string[1] { "Fish11" }); action(7, new string[1] { "Fish10" }); action(8, new string[5] { "SerpentMeat", "SerpentScale", "Chitin", "Fish3", "Fish8" }); action(9, new string[19] { "Wood", "Stone", "StoneRock", "Coal", "Egg", "ChickenEgg", "ChickenMeat", "Feathers", "FishingBait", "Thunderstone", "YmirRemains", "BarrelRings", "Tankard", "Coins", "AncientCoin", "Amber", "AmberPearl", "Ruby", "SilverNecklace" }); AddResearched(action); return map; } internal static int SortKey(ItemData item) { string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (!TrophyBiomes.PositionOf(text, out var position)) { position = ((text == null || !order.TryGetValue(text, out position)) ? 9999 : (position + 100)); } return Of(item) * 10000 + position; } internal static int Of(ItemData item) { string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); if (text == null) { return 9; } EnsureBuilt(); if (!resolved.TryGetValue(text, out var value)) { value = Resolve(text, new HashSet<string>()); } if (value != 99) { return value; } return 9; } private static void EnsureBuilt() { if (built || (Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || ObjectDB.instance.m_items.Count == 0) { return; } built = true; foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!((Object)(object)recipe == (Object)null) && recipe.m_enabled && !((Object)(object)recipe.m_item == (Object)null) && recipe.m_resources != null) { string[] inputs = (from r in recipe.m_resources where r != null && (Object)(object)r.m_resItem != (Object)null select ((Object)((Component)r.m_resItem).gameObject).name).ToArray(); AddSource(((Object)((Component)recipe.m_item).gameObject).name, inputs, recipe.m_requireOnlyOneIngredient); } } foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } Smelter component = prefab.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null && component.m_conversion != null) { foreach (ItemConversion item in component.m_conversion) { AddConversion(item.m_from, item.m_to); } } CookingStation component2 = prefab.GetComponent<CookingStation>(); if ((Object)(object)component2 != (Object)null && component2.m_conversion != null) { foreach (ItemConversion item2 in component2.m_conversion) { AddConversion(item2.m_from, item2.m_to); } } Fermenter component3 = prefab.GetComponent<Fermenter>(); if (!((Object)(object)component3 != (Object)null) || component3.m_conversion == null) { continue; } foreach (ItemConversion item3 in component3.m_conversion) { AddConversion(item3.m_from, item3.m_to); } } LogUnresolved(); } private static void AddConversion(ItemDrop from, ItemDrop to) { if ((Object)(object)from != (Object)null && (Object)(object)to != (Object)null) { AddSource(((Object)((Component)to).gameObject).name, new string[1] { ((Object)((Component)from).gameObject).name }, anyInput: false); } } private static void AddSource(string item, string[] inputs, bool anyInput) { if (inputs.Length != 0) { if (!sources.TryGetValue(item, out var value)) { value = new List<Source>(); sources[item] = value; } value.Add(new Source { Inputs = inputs, AnyInput = anyInput }); } } private static int Resolve(string name, HashSet<string> path) { if (resolved.TryGetValue(name, out var value)) { return value; } int value2 = TrophyBiomes.Of(name); if (value2 == 99 && !raw.TryGetValue(name, out value2)) { value2 = 99; } if (value2 != 99) { resolved[name] = value2; return value2; } if (!path.Add(name)) { return 99; } int num = 99; if (sources.TryGetValue(name, out var value3)) { foreach (Source item in value3) { List<int> list = (from input in item.Inputs select Resolve(input, path) into v where v != 99 select v).ToList(); if (list.Count == 0) { continue; } if (list.Any((int v) => v != 9)) { list.RemoveAll((int v) => v == 9); } int val = (item.AnyInput ? list.Min() : list.Max()); num = Math.Min(num, val); } } path.Remove(name); resolved[name] = num; return num; } private static void LogUnresolved() { List<string> list = new List<string>(); foreach (GameObject item in ObjectDB.instance.m_items) { if ((Object)(object)item != (Object)null && Resolve(((Object)item).name, new HashSet<string>()) == 99) { list.Add(((Object)item).name); } } list.Sort(StringComparer.Ordinal); SortingTweaksPlugin.Log.LogInfo((object)("Items without a biome (" + list.Count + "): " + string.Join(", ", list.ToArray()))); } private static void AddResearched(Action<int, string[]> add) { add(0, new string[3] { "ArrowFire", "ArrowFlint", "Torch" }); add(1, new string[4] { "BronzeScrap", "Ectoplasm", "Pukeberries", "RoundLog" }); add(2, new string[3] { "ArrowIron", "ArrowPoison", "WrithanRoots" }); add(3, new string[8] { "ArrowFrost", "chest_hildir2", "Upgrader3Armor", "Upgrader3Weapon", "Upgrader4Armor", "Upgrader4Weapon", "WolfClaw", "WolfHairBundle" }); add(4, new string[3] { "chest_hildir3", "UndeadBjornRibcage", "YagluthDrop" }); add(5, new string[5] { "DvergrKeyFragment", "DvergrNeedle", "GiantBloodSack", "QueenDrop", "Wisp" }); add(6, new string[22] { "AsksvinCarrionNeck", "AsksvinCarrionPelvic", "AsksvinCarrionRibcage", "AsksvinCarrionSkull", "BellFragment", "Blackwood", "BonemawSerpentTooth", "CharcoalResin", "CharredBone", "CharredCogwheel", "Charredskull", "DyrnwynBladeFragment", "DyrnwynHiltFragment", "DyrnwynTipFragment", "GemstoneBlue", "GemstoneGreen", "GemstoneRed", "MoltenCore", "Pot_Shard_Green", "ProustitePowder", "SulfurStone", "VineberrySeeds" }); add(7, new string[31] { "BloodGoldKey", "CrownJewel", "FirConeFrost", "Frostwood", "FrozenKingDrop", "GlowWorm", "GoldOre", "Leatherstraps", "MoldArmorGoldChest", "MoldArmorGoldHelmet", "MoldArmorGoldLegs", "MoldArmorMageChest", "MoldArmorMageHelmet", "MoldArmorMageLegs", "MoldArmormediumChest", "MoldArmorMediumHelmet", "MoldArmorMediumLegs", "MoldAxe", "MoldBow", "MoldKeys", "MoldMace", "MoldSpear", "MoldSword", "OozeMork", "OrbFrostFire", "OrbThunderBlood", "Snowball", "Upgrader6Armor", "Upgrader6Weapon", "Upgrader7Armor", "Upgrader7Weapon" }); add(9, new string[49] { "ArmorDress10", "ArmorDress2", "ArmorDress3", "ArmorDress5", "ArmorDress6", "ArmorDress8", "ArmorDress9", "ArmorHarvester1", "ArmorHarvester2", "ArmorTunic10", "ArmorTunic2", "ArmorTunic3", "ArmorTunic5", "ArmorTunic6", "ArmorTunic8", "ArmorTunic9", "BlobVial", "CandleWick", "CuredSquirrelHamstring", "FireworksRocket_White", "FragrantBundle", "FreshSeaweed", "HelmetHat1", "HelmetHat10", "HelmetHat2", "HelmetHat3", "HelmetHat4", "HelmetHat5", "HelmetHat6", "HelmetHat7", "HelmetHat8", "HelmetHat9", "HelmetRootCrown", "HelmetStrawHat", "HelmetSweatBand", "Ironpit", "MeadTrollPheromones", "MushroomBzerker", "PowderedDragonEgg", "PungentPebbles", "ScytheHandle", "SpiceAshlands", "SpiceDeepNorth", "SpiceForests", "SpiceMistlands", "SpiceMountains", "SpiceOceans", "SpicePlains", "VineGreenSeeds" }); } } [BepInPlugin("sortingtweaks.valheim", "Sorting Tweaks", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class SortingTweaksPlugin : BaseUnityPlugin { public const string PluginGuid = "sortingtweaks.valheim"; public const string PluginName = "Sorting Tweaks"; public const string PluginVersion = "1.1.0"; internal const string QuickStackStoreGuid = "goldenrevolver.quick_stack_store"; internal const string FoodCategoriesGuid = "branchofyore.foodcategories"; internal static ManualLogSource Log; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Harmony harmony = new Harmony("sortingtweaks.valheim"); TabSound.Init((BaseUnityPlugin)(object)this, harmony); if (Chainloader.PluginInfos.ContainsKey("goldenrevolver.quick_stack_store")) { ContainerSort.Init((BaseUnityPlugin)(object)this, harmony); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Quick Stack Store is not installed, per-container sort is off."); } if (Chainloader.PluginInfos.ContainsKey("branchofyore.foodcategories")) { FoodTweaks.Init((BaseUnityPlugin)(object)this, harmony); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Food Categories is not installed, the food tweaks are off."); } } } internal static class TabSound { private static ConfigEntry<bool> quietTabSwitch; private static ConfigEntry<bool> quietMouseClick; private static bool inTabHandler; internal static void Init(BaseUnityPlugin plugin, Harmony harmony) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown quietTabSwitch = plugin.Config.Bind<bool>("Crafting", "QuietTabSwitch", true, "Play only the click sound when switching between the Craft and Upgrade tab, not the extra group change sound right after it."); quietMouseClick = plugin.Config.Bind<bool>("Interface", "QuietMouseClick", true, "Clicking a button with the mouse plays the select sound on press and the click sound on release. At a high frame rate both are audible as a double click, so skip the select sound for mouse clicks."); MethodInfo methodInfo = AccessTools.Method(typeof(ButtonSfx), "OnSelect", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(TabSound), "SkipMouseSelect", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo2 = AccessTools.Method(typeof(InventoryGui), "SetActiveGroup", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(InventoryGui), "OnTabCraftPressed", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(InventoryGui), "OnTabUpgradePressed", (Type[])null, (Type[])null); if (methodInfo2 == null || methodInfo3 == null || methodInfo4 == null) { SortingTweaksPlugin.Log.LogWarning((object)"Tab switch methods not found (incompatible Valheim version?), the tab sound tweak is off."); return; } HarmonyMethod val = new HarmonyMethod(typeof(TabSound), "EnterTabHandler", (Type[])null); HarmonyMethod val2 = new HarmonyMethod(typeof(TabSound), "LeaveTabHandler", (Type[])null); harmony.Patch((MethodBase)methodInfo3, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(TabSound), "MuteGroupSound", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool SkipMouseSelect(BaseEventData eventData) { if (quietMouseClick.Value) { return !(eventData is PointerEventData); } return true; } private static void EnterTabHandler() { inTabHandler = true; } private static void LeaveTabHandler() { inTabHandler = false; } private static void MuteGroupSound(ref bool playSound) { if (inTabHandler && quietTabSwitch.Value) { playSound = false; } } } internal static class TrophyBiomes { internal const int Unknown = 99; private static readonly string[][] biomes = new string[9][] { new string[4] { "TrophyBoar", "TrophyDeer", "TrophyNeck", "TrophyEikthyr" }, new string[10] { "TrophyGreydwarf", "TrophyGreydwarfBrute", "TrophyGreydwarfShaman", "TrophySkeletonPoison", "TrophySkeleton", "TrophyGhost", "TrophyFrostTroll", "TrophyBjorn", "TrophySkeletonHildir", "TrophyTheElder" }, new string[10] { "TrophyAbomination", "TrophyBlob", "TrophyDraugr", "TrophyDraugrElite", "TrophyLeech", "TrophySurtling", "TrophyWraith", "TrophyKvastur", "TrophyWrithan", "TrophyBonemass" }, new string[9] { "TrophyCultist", "TrophyHatchling", "TrophyFenring", "TrophyBlob_Frost", "TrophySGolem", "TrophyUlv", "TrophyWolf", "TrophyCultist_Hildir", "TrophyDragonQueen" }, new string[10] { "TrophyDeathsquito", "TrophyGoblin", "TrophyGoblinBrute", "TrophyGoblinShaman", "TrophyGrowth", "TrophyLox", "TrophyBjornUndead", "TrophyGoblinBruteBrosShaman", "TrophyGoblinBruteBrosBrute", "TrophyGoblinKing" }, new string[7] { "TrophyDvergr", "TrophyHare", "TrophyGjall", "TrophySeeker", "TrophySeekerBrute", "TrophyTick", "TrophySeekerQueen" }, new string[10] { "TrophyAsksvin", "TrophyBonemawSerpent", "TrophyFallenValkyrie", "TrophyCharredArcher", "TrophyMorgen", "TrophyVolture", "TrophyCharredMage", "TrophyCharredMelee", "TrophyBlob_Lava", "TrophyFader" }, new string[8] { "TrophyBarka", "TrophyElaking", "TrophyMole", "TrophyJotunWitch", "TrophyJotunWarrior", "TrophyMoose", "TrophyBlob_Morkhalla", "TrophySeal" }, new string[1] { "TrophySerpent" } }; private static readonly Dictionary<string, int> positions = new Dictionary<string, int>(); private static readonly Dictionary<string, int> byPrefab = Build(); private static Dictionary<string, int> Build() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); for (int i = 0; i < biomes.Length; i++) { for (int j = 0; j < biomes[i].Length; j++) { dictionary[biomes[i][j]] = i; positions[biomes[i][j]] = j; } } return dictionary; } internal static bool PositionOf(string prefab, out int position) { position = 0; if (prefab != null) { return positions.TryGetValue(prefab, out position); } return false; } internal static int Of(string prefab) { if (prefab == null || !byPrefab.TryGetValue(prefab, out var value)) { return 99; } return value; } }