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 WorkbenchesPlus v1.0.2
plugins/WorkbenchesPlus/WorkbenchesPlus.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; 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.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("WorkbenchesPlus")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+279192a2c58228e53c616183abeb60b04b7ecdc5")] [assembly: AssemblyProduct("Workbenches+")] [assembly: AssemblyTitle("WorkbenchesPlus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] namespace WorkbenchesPlus; public class ModConfig { public ConfigEntry<bool> EnableMod { get; } public ConfigEntry<bool> EnableCategories { get; } public ConfigEntry<bool> EnableCraftableFirst { get; } public ConfigEntry<bool> EnableArmorSetGrouping { get; } public ConfigEntry<bool> EnableWeaponSetGrouping { get; } public ConfigEntry<bool> EnableToolSetGrouping { get; } public ConfigEntry<bool> EnableShieldSetGrouping { get; } public ConfigEntry<bool> EnableMaterialSectionHeaders { get; } public ConfigEntry<string> SortMode { get; } public ConfigEntry<string> ArmorPieceOrder { get; } public ConfigEntry<string> WeaponPieceOrder { get; } public ConfigEntry<string> ToolPieceOrder { get; } public ConfigEntry<string> ShieldPieceOrder { get; } public ConfigEntry<bool> GroupModdedArmorSets { get; } public ConfigEntry<bool> GroupModdedWeaponSets { get; } public ConfigEntry<bool> RefreshOnInventoryChange { get; } public ConfigEntry<bool> RefreshOnStationChange { get; } public ConfigEntry<bool> ShowCraftabilityIndicators { get; } public ConfigEntry<bool> EnableCraftMultiplier { get; } public ConfigEntry<int> MaxCraftMultiplier { get; } public ConfigEntry<bool> EnableDismantle { get; } public ConfigEntry<bool> DebugLogging { get; } public ModConfig(ConfigFile file) { EnableMod = file.Bind<bool>("1 - General", "EnableMod", true, "Master switch for Workbenches+."); EnableCategories = file.Bind<bool>("1 - General", "EnableCategories", true, "Show category chips above the crafting recipe list."); EnableCraftableFirst = file.Bind<bool>("2 - Sorting", "EnableCraftableFirst", true, "When SortMode is CraftableFirst / CategoryThenCraftable, prioritize craftable recipes."); EnableArmorSetGrouping = file.Bind<bool>("2 - Sorting", "EnableArmorSetGrouping", true, "Keep armor pieces from the same set next to each other."); EnableWeaponSetGrouping = file.Bind<bool>("2 - Sorting", "EnableWeaponSetGrouping", true, "Keep weapons of the same material together (Iron, BlackMetal, Bronze, …)."); EnableToolSetGrouping = file.Bind<bool>("2 - Sorting", "EnableToolSetGrouping", true, "Keep tools of the same material together (Antler, Bronze, Iron, BlackMetal, …)."); EnableShieldSetGrouping = file.Bind<bool>("2 - Sorting", "EnableShieldSetGrouping", true, "Keep shields of the same material together (Wood, Bronze, Iron, BlackMetal, …)."); EnableMaterialSectionHeaders = file.Bind<bool>("2 - Sorting", "EnableMaterialSectionHeaders", true, "Show section labels between material groups (IRON, BRONZE, Arrows — left-aligned)."); SortMode = file.Bind<string>("2 - Sorting", "SortMode", "CraftableFirst", "CraftableFirst | CategoryThenCraftable | Progression | Alphabetical | Vanilla"); ArmorPieceOrder = file.Bind<string>("3 - Armor", "ArmorPieceOrder", "Chest,Helmet,Legs,Cape,Other", "Comma-separated piece order within an armor set."); GroupModdedArmorSets = file.Bind<bool>("3 - Armor", "GroupModdedArmorSets", true, "Apply set-name heuristics to non-vanilla armor prefabs."); WeaponPieceOrder = file.Bind<string>("3b - Weapons", "WeaponPieceOrder", "Arrow,Bolt,Knife,Sword,Mace,Axe,Battleaxe,Spear,Atgeir,Sledge,Bow,Crossbow,Club,Bomb,Pickaxe,Other", "Comma-separated weapon type order within a material group. Arrows first by default."); GroupModdedWeaponSets = file.Bind<bool>("3b - Weapons", "GroupModdedWeaponSets", true, "Apply material heuristics to non-vanilla weapon prefabs."); ToolPieceOrder = file.Bind<string>("3c - Tools", "ToolPieceOrder", "Hammer,Hoe,Cultivator,Pickaxe,Scythe,Other", "Comma-separated tool type order within a material group."); ShieldPieceOrder = file.Bind<string>("3d - Shields", "ShieldPieceOrder", "Shield,Tower,Other", "Comma-separated shield type order within a material group."); RefreshOnInventoryChange = file.Bind<bool>("4 - Refresh", "RefreshOnInventoryChange", true, "Re-sort when the local player inventory changes while crafting is open."); RefreshOnStationChange = file.Bind<bool>("4 - Refresh", "RefreshOnStationChange", true, "Reset category to All when switching crafting stations."); ShowCraftabilityIndicators = file.Bind<bool>("5 - UI", "ShowCraftabilityIndicators", false, "Show a small green checkmark on fully craftable recipe rows."); EnableCraftMultiplier = file.Bind<bool>("5 - UI", "EnableCraftMultiplier", true, "Show up/down arrows beside the Craft button for multi-craft amount."); MaxCraftMultiplier = file.Bind<int>("5 - UI", "MaxCraftMultiplier", 99, "Upper cap for the craft multiplier (materials still limit how high you can go)."); EnableDismantle = file.Bind<bool>("5 - UI", "EnableDismantle", true, "Show a Dismantle tab beside Craft/Upgrade to break items back into crafting materials."); DebugLogging = file.Bind<bool>("9 - Debug", "DebugLogging", false, "Extra log lines for sorting decisions (set keys, order)."); } public string Mode() { return (SortMode.Value ?? "CraftableFirst").Trim(); } public bool IsVanillaOrder() { return Mode().Equals("Vanilla", StringComparison.OrdinalIgnoreCase); } public bool IsAlphabetical() { return Mode().Equals("Alphabetical", StringComparison.OrdinalIgnoreCase); } public bool IsProgression() { return Mode().Equals("Progression", StringComparison.OrdinalIgnoreCase); } public bool IsCategoryThenCraftable() { return Mode().Equals("CategoryThenCraftable", StringComparison.OrdinalIgnoreCase); } public bool UseCraftBuckets() { if (!EnableCraftableFirst.Value) { return false; } string text = Mode(); if (!text.Equals("CraftableFirst", StringComparison.OrdinalIgnoreCase) && !text.Equals("CategoryThenCraftable", StringComparison.OrdinalIgnoreCase)) { return string.IsNullOrEmpty(text); } return true; } } internal static class ArmorSetDetector { private static readonly string[] StripSuffixes = new string[19] { "Helmet", "Hood", "Hat", "Circlet", "Crown", "Chest", "Jacket", "Tunic", "Cuirass", "Armor", "Legs", "Greaves", "Pants", "Trousers", "Skirt", "Cape", "Cloak", "Mantle", "Shoulder" }; private static readonly string[] KnownSetStems = new string[19] { "TrollLeather", "Carapace", "Ashlands", "Fenring", "Fenris", "Padded", "Bronze", "Iron", "Wolf", "Root", "Mage", "Eitr", "Leather", "Rags", "Rag", "Himmin", "Asksvin", "Embla", "Flametal" }; private static readonly Regex SharedCleanup = new Regex("^\\$?(item[_-]?)?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedPieceTrim = new Regex("[_-]?(helmet|hood|hat|circlet|crown|chest|jacket|tunic|cuirass|legs|greaves|pants|trousers|skirt|cape|cloak|mantle|shoulder|armor)$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedPiecePrefix = new Regex("^(helmet|hood|hat|chest|legs|cape|armor|trousers|tunic)[_-]", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static string SetKey(Recipe recipe, bool groupModded) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)recipe == (Object)null) { return null; } ItemType itemType = GetItemType(recipe); string text = PrefabName(recipe) ?? ""; string text2 = SharedName(recipe) ?? ""; string blob = (text + " " + text2).Trim(); if (!IsArmorPiece(itemType, text, text2)) { return null; } string text3 = FromPrefab(text); if (string.IsNullOrEmpty(text3)) { text3 = FromShared(text2); } if (string.IsNullOrEmpty(text3)) { text3 = FromKnownStem(blob); } text3 = Canonicalize(text3); if (string.IsNullOrEmpty(text3) || text3.Length < 4) { return null; } if (IsSlotType(itemType) || LooksLikeArmorName(blob)) { return text3; } if (!groupModded && !text3.StartsWith("Armor", StringComparison.OrdinalIgnoreCase) && !text3.StartsWith("Cape", StringComparison.OrdinalIgnoreCase)) { return null; } return text3; } private static bool LooksLikeArmorName(string blob) { if (string.IsNullOrEmpty(blob)) { return false; } if (blob.IndexOf("armor", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("leather", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("troll", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("bronze", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("padded", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("carapace", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("fenring", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("fenris", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("rag", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("cape", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("helmet", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("tunic", StringComparison.OrdinalIgnoreCase) < 0 && blob.IndexOf("trousers", StringComparison.OrdinalIgnoreCase) < 0) { return blob.IndexOf("greaves", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool IsSlotType(ItemType t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 if ((int)t != 6 && (int)t != 7 && (int)t != 11) { return (int)t == 17; } return true; } private static bool IsArmorPiece(ItemType t, string prefab, string shared) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (IsSlotType(t)) { return true; } string text = prefab + " " + shared; for (int i = 0; i < StripSuffixes.Length; i++) { if (text.IndexOf(StripSuffixes[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } if (!prefab.StartsWith("Armor", StringComparison.OrdinalIgnoreCase) && !prefab.StartsWith("Cape", StringComparison.OrdinalIgnoreCase)) { return prefab.StartsWith("Helmet", StringComparison.OrdinalIgnoreCase); } return true; } private static string FromPrefab(string prefab) { if (string.IsNullOrEmpty(prefab)) { return null; } if (prefab.Equals("HelmetDrake", StringComparison.OrdinalIgnoreCase)) { return "ArmorWolf"; } if (prefab.Equals("HelmetBerserkerUndead", StringComparison.OrdinalIgnoreCase) || prefab.Equals("ArmorBerserkerUndeadChest", StringComparison.OrdinalIgnoreCase) || prefab.Equals("ArmorBerserkerUndeadLegs", StringComparison.OrdinalIgnoreCase)) { return "ArmorVilebone"; } if (prefab.StartsWith("Helmet", StringComparison.OrdinalIgnoreCase) && prefab.Length > 6) { string text = prefab.Substring(6); if (IsStandaloneHelmet(text)) { return "Helmet" + text; } return "Armor" + text; } if (prefab.StartsWith("Cape", StringComparison.OrdinalIgnoreCase) && prefab.Length > 4) { string text2 = prefab.Substring(4); if (IsSetCape(text2)) { return "Armor" + text2; } return "Cape" + text2; } string text3 = prefab; bool flag = false; for (int i = 0; i < 2; i++) { for (int j = 0; j < StripSuffixes.Length; j++) { string text4 = StripSuffixes[j]; if (!text4.Equals("Armor", StringComparison.OrdinalIgnoreCase) && text3.EndsWith(text4, StringComparison.OrdinalIgnoreCase) && text3.Length > text4.Length + 3) { text3 = text3.Substring(0, text3.Length - text4.Length); flag = true; break; } } } if (!flag && !text3.StartsWith("Armor", StringComparison.OrdinalIgnoreCase)) { return null; } return text3; } private static string FromShared(string shared) { if (string.IsNullOrEmpty(shared)) { return null; } string text = SharedCleanup.Replace(shared, ""); for (int i = 0; i < 3; i++) { string input = SharedPieceTrim.Replace(text, ""); input = SharedPiecePrefix.Replace(input, ""); input = input.Trim('_', '-', ' '); if (input == text) { break; } text = input; } if (text.Length < 3) { return null; } return text; } private static string FromKnownStem(string blob) { if (string.IsNullOrEmpty(blob)) { return null; } for (int i = 0; i < KnownSetStems.Length; i++) { if (blob.IndexOf(KnownSetStems[i], StringComparison.OrdinalIgnoreCase) >= 0) { return "Armor" + KnownSetStems[i]; } } return null; } private static string Canonicalize(string raw) { if (string.IsNullOrEmpty(raw)) { return null; } string text = raw.Replace("-", "_"); if (text.IndexOf('_') >= 0) { string[] array = text.Split(new char[1] { '_' }); StringBuilder stringBuilder = new StringBuilder(); foreach (string text2 in array) { if (!string.IsNullOrEmpty(text2)) { stringBuilder.Append(char.ToUpperInvariant(text2[0])); if (text2.Length > 1) { stringBuilder.Append(text2.Substring(1)); } } } text = stringBuilder.ToString(); } if (text.Length > 0 && char.IsLower(text[0])) { text = char.ToUpperInvariant(text[0]) + text.Substring(1); } if (!text.StartsWith("Armor", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("Cape", StringComparison.OrdinalIgnoreCase) && !text.StartsWith("Helmet", StringComparison.OrdinalIgnoreCase)) { text = "Armor" + text; } if (text.StartsWith("ArmorArmor", StringComparison.OrdinalIgnoreCase)) { text = "Armor" + text.Substring("ArmorArmor".Length); } if (text.Equals("ArmorRag", StringComparison.OrdinalIgnoreCase)) { return "ArmorRags"; } if (text.Equals("ArmorTroll", StringComparison.OrdinalIgnoreCase)) { return "ArmorTrollLeather"; } if (text.Equals("ArmorFenris", StringComparison.OrdinalIgnoreCase)) { return "ArmorFenring"; } if (text.Equals("ArmorPadd", StringComparison.OrdinalIgnoreCase)) { return "ArmorPadded"; } return text; } private static bool IsStandaloneHelmet(string rest) { if (!rest.Equals("Yule", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Dverger", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Fisherman", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Hat", StringComparison.OrdinalIgnoreCase)) { return rest.Equals("PointyHat", StringComparison.OrdinalIgnoreCase); } return true; } private static bool IsSetCape(string rest) { if (!rest.Equals("Wolf", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Troll", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Lox", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Feather", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Asksvin", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Carapace", StringComparison.OrdinalIgnoreCase) && !rest.Equals("Ashlands", StringComparison.OrdinalIgnoreCase)) { return rest.Equals("Fenring", StringComparison.OrdinalIgnoreCase); } return true; } public static int PieceOrder(Recipe recipe, string[] orderTokens) { //IL_0001: 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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Invalid comparison between Unknown and I4 ItemType itemType = GetItemType(recipe); if ((int)itemType == 7) { return IndexOf(orderTokens, "Chest"); } if ((int)itemType == 6) { return IndexOf(orderTokens, "Helmet"); } if ((int)itemType == 11) { return IndexOf(orderTokens, "Legs"); } if ((int)itemType == 17) { return IndexOf(orderTokens, "Cape"); } string text = PrefabName(recipe) ?? ""; for (int i = 0; i < orderTokens.Length; i++) { string text2 = orderTokens[i]; if (!string.IsNullOrEmpty(text2) && !text2.Equals("Other", StringComparison.OrdinalIgnoreCase) && text.IndexOf(text2, StringComparison.OrdinalIgnoreCase) >= 0) { return i; } } return orderTokens.Length + 10; } public static string[] ParseOrder(string csv) { if (string.IsNullOrEmpty(csv)) { return new string[5] { "Chest", "Helmet", "Legs", "Cape", "Other" }; } string[] array = csv.Split(new char[1] { ',' }); List<string> list = new List<string>(); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } if (list.Count == 0) { list.AddRange(new string[5] { "Chest", "Helmet", "Legs", "Cape", "Other" }); } return list.ToArray(); } private static string PrefabName(Recipe recipe) { if ((Object)(object)recipe?.m_item == (Object)null) { return null; } string name = ((Object)recipe.m_item).name; if (!string.IsNullOrEmpty(name)) { return name; } if (!((Object)(object)((Component)recipe.m_item).gameObject != (Object)null)) { return null; } return ((Object)((Component)recipe.m_item).gameObject).name; } private static string SharedName(Recipe recipe) { try { return recipe?.m_item?.m_itemData?.m_shared?.m_name; } catch { return null; } } private static ItemType GetItemType(Recipe recipe) { //IL_0036: 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_0045: Unknown result type (might be due to invalid IL or missing references) try { if (recipe?.m_item?.m_itemData?.m_shared != null) { return recipe.m_item.m_itemData.m_shared.m_itemType; } } catch { } return (ItemType)0; } private static int IndexOf(string[] order, string token) { for (int i = 0; i < order.Length; i++) { if (order[i].Equals(token, StringComparison.OrdinalIgnoreCase)) { return i; } } return order.Length + 5; } } internal static class Craftability { public const int BucketFully = 0; public const int BucketPartial = 1; public const int BucketNone = 2; public const int BucketBlocked = 3; public static int ScoreBucket(Player player, Recipe recipe) { if ((Object)(object)player == (Object)null || (Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return 3; } try { if (player.HaveRequirements(recipe, false, 1, 1)) { return 0; } } catch (Exception ex) { if (Plugin.Settings != null && Plugin.Settings.DebugLogging.Value) { Plugin.Log.LogWarning((object)("HaveRequirements: " + ex.Message)); } } int num = 0; int num2 = 0; Requirement[] resources = recipe.m_resources; if (resources == null || resources.Length == 0) { return 2; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return 2; } foreach (Requirement val in resources) { if (val == null || (Object)(object)val.m_resItem == (Object)null || val.m_resItem.m_itemData == null) { continue; } int amount = val.GetAmount(1); if (amount > 0) { num2++; string name = val.m_resItem.m_itemData.m_shared.m_name; if (inventory.CountItems(name, -1, true) >= amount) { num++; } } } if (num2 <= 0) { return 2; } if (num <= 0) { return 2; } if (num >= num2) { return 3; } return 1; } public static int MaterialPercent(Player player, Recipe recipe) { if ((Object)(object)player == (Object)null || recipe?.m_resources == null) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return 0; } int num = 0; int num2 = 0; Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if (val?.m_resItem?.m_itemData?.m_shared != null) { int amount = val.GetAmount(1); if (amount > 0) { num += amount; string name = val.m_resItem.m_itemData.m_shared.m_name; num2 += Math.Min(amount, inventory.CountItems(name, -1, true)); } } } if (num <= 0) { return 0; } return num2 * 100 / num; } } internal static class DismantleMode { public static readonly List<ItemData> Items = new List<ItemData>(); private static ItemData _progressItem; private static Recipe _progressRecipe; private static readonly FieldInfo CraftRecipeField = AccessTools.Field(typeof(InventoryGui), "m_craftRecipe"); private static readonly FieldInfo CraftUpgradeItemField = AccessTools.Field(typeof(InventoryGui), "m_craftUpgradeItem"); private static readonly FieldInfo CraftTimerField = AccessTools.Field(typeof(InventoryGui), "m_craftTimer"); private static readonly FieldInfo CraftItemEffectsField = AccessTools.Field(typeof(InventoryGui), "m_craftItemEffects"); private static readonly FieldInfo CraftItemDoneEffectsField = AccessTools.Field(typeof(InventoryGui), "m_craftItemDoneEffects"); private static readonly FieldInfo CraftingVibrationField = AccessTools.Field(typeof(InventoryGui), "CraftingVibration"); public static bool Active { get; private set; } public static bool HasProgress => _progressItem != null; public static void SetActive(bool on) { Active = on; if (!on) { Items.Clear(); CancelProgress(null); } } public static void EnterFromUi(InventoryGui gui) { if (!((Object)(object)gui == (Object)null)) { SetActive(on: true); Button val = AccessToolsExt.TabCraft(gui); Button val2 = AccessToolsExt.TabUpgrade(gui); if ((Object)(object)val != (Object)null) { ((Selectable)val).interactable = true; } if ((Object)(object)val2 != (Object)null) { ((Selectable)val2).interactable = true; } CraftMultiplierBar.ForceHideArrows(); DismantleTab.RefreshVisuals(gui); AccessToolsExt.RebuildCraftingPanel(); DismantleTab.RefreshVisuals(gui); } } public static void ClearIfNotSuppressed() { if (Active) { SetActive(on: false); DismantleTab.RefreshVisuals(InventoryGui.instance); } } public static void BuildList(List<Recipe> recipes) { Items.Clear(); if (recipes == null) { return; } recipes.Clear(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null) { return; } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null || allItems.Count == 0) { return; } for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (val != null && val.m_shared != null && !val.m_equipped && TryGetDismantleRecipe(localPlayer, currentCraftingStation, val, out var recipe)) { recipes.Add(recipe); Items.Add(val); } } } public static bool CanDismantle(Player player, CraftingStation station, ItemData item) { Recipe recipe; return TryGetDismantleRecipe(player, station, item, out recipe); } private static bool TryGetDismantleRecipe(Player player, CraftingStation station, ItemData item, out Recipe recipe) { recipe = null; if ((Object)(object)player == (Object)null || item?.m_shared == null) { return false; } if (item.m_equipped) { return false; } recipe = FindRecipe(item, station); if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null) { return false; } if (!StationFilter.BelongsToStation(recipe, station)) { return false; } int num = Mathf.Max(1, recipe.m_amount); if (item.m_stack < num) { return false; } return true; } public static void SortPaired(List<Recipe> recipes) { if (recipes != null && Items.Count == recipes.Count) { List<int> list = new List<int>(recipes.Count); for (int i = 0; i < recipes.Count; i++) { list.Add(i); } list.Sort(delegate(int a, int b) { string strA = ItemSortName(Items[a]); string strB = ItemSortName(Items[b]); int num3 = string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); return (num3 != 0) ? num3 : a.CompareTo(b); }); List<Recipe> list2 = new List<Recipe>(recipes.Count); List<ItemData> list3 = new List<ItemData>(Items.Count); for (int num = 0; num < list.Count; num++) { int index = list[num]; list2.Add(recipes[index]); list3.Add(Items[index]); } recipes.Clear(); Items.Clear(); for (int num2 = 0; num2 < list2.Count; num2++) { recipes.Add(list2[num2]); Items.Add(list3[num2]); } } } private static string ItemSortName(ItemData item) { try { if (item?.m_shared != null) { return item.m_shared.m_name ?? ""; } } catch { } return ""; } public static Recipe FindRecipe(ItemData item, CraftingStation station) { if (item?.m_shared == null || (Object)(object)ObjectDB.instance == (Object)null) { return null; } try { Recipe recipe = ObjectDB.instance.GetRecipe(item); if ((Object)(object)recipe != (Object)null && StationFilter.BelongsToStation(recipe, station)) { return recipe; } } catch { } List<Recipe> recipes = ObjectDB.instance.m_recipes; if (recipes == null) { return null; } string value = ResolvePrefabName(item); if (string.IsNullOrEmpty(value)) { return null; } Recipe val = null; for (int i = 0; i < recipes.Count; i++) { Recipe val2 = recipes[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)val2.m_item == (Object)null) { continue; } try { if (!val2.m_enabled) { continue; } } catch { } if (((Object)val2.m_item).name.Equals(value, StringComparison.OrdinalIgnoreCase)) { if (StationFilter.BelongsToStation(val2, station)) { return val2; } if ((Object)(object)val == (Object)null) { val = val2; } } } if ((Object)(object)val != (Object)null && StationFilter.BelongsToStation(val, station)) { return val; } return null; } private static string ResolvePrefabName(ItemData item) { if (item == null) { return null; } if ((Object)(object)item.m_dropPrefab != (Object)null && !string.IsNullOrEmpty(((Object)item.m_dropPrefab).name)) { return StripClone(((Object)item.m_dropPrefab).name); } if ((Object)(object)ObjectDB.instance == (Object)null || item.m_shared == null) { return null; } try { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item.m_shared); if ((Object)(object)itemPrefab != (Object)null) { return StripClone(((Object)itemPrefab).name); } } catch { } return null; } private static string StripClone(string name) { if (string.IsNullOrEmpty(name)) { return name; } if (name.EndsWith("(Clone)", StringComparison.Ordinal)) { return name.Substring(0, name.Length - "(Clone)".Length).Trim(); } return name; } public static List<KeyValuePair<ItemDrop, int>> BuildRefund(Recipe recipe, int quality) { List<KeyValuePair<ItemDrop, int>> list = new List<KeyValuePair<ItemDrop, int>>(); if (recipe?.m_resources == null) { return list; } if (quality < 1) { quality = 1; } Dictionary<string, ItemDrop> dictionary = new Dictionary<string, ItemDrop>(StringComparer.OrdinalIgnoreCase); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val?.m_resItem == (Object)null || IsIdolOrUpgraderResource(val)) { continue; } int num = CraftMaterialAmount(val, quality); if (num > 0) { ItemDrop resItem = val.m_resItem; string name = ((Object)resItem).name; if (!string.IsNullOrEmpty(name)) { dictionary[name] = resItem; dictionary2.TryGetValue(name, out var value); dictionary2[name] = value + num; } } } foreach (KeyValuePair<string, int> item in dictionary2) { if (dictionary.TryGetValue(item.Key, out var value2) && !((Object)(object)value2 == (Object)null) && item.Value > 0) { list.Add(new KeyValuePair<ItemDrop, int>(value2, item.Value)); } } return list; } private static bool IsIdolOrUpgraderResource(Requirement req) { if (req == null) { return true; } try { if (req.m_upgraderResource) { return true; } } catch { } ItemDrop resItem = req.m_resItem; if ((Object)(object)resItem == (Object)null) { return true; } if ((((Object)resItem).name ?? "").StartsWith("Upgrader", StringComparison.OrdinalIgnoreCase)) { return true; } try { if ((resItem.m_itemData?.m_shared?.m_name ?? "").IndexOf("idol", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } catch { } return false; } private static int CraftMaterialAmount(Requirement req, int quality) { if (req == null || quality < 1) { return 0; } int num = 0; for (int i = 1; i <= quality; i++) { if (i <= 1) { num += Mathf.Max(0, req.m_amount); continue; } float num2 = ((i >= 4) ? (4f + (float)(i - 4) / 2f) : ((float)(i - 1))); num += Mathf.FloorToInt(num2 * (float)req.m_amountPerLevel); } return num; } public static void BindSelectedItem(InventoryGui gui, int index) { if (Active && !((Object)(object)gui == (Object)null) && index >= 0 && index < Items.Count && CraftUpgradeItemField != null) { CraftUpgradeItemField.SetValue(gui, Items[index]); } } public static ItemData ResolveSelectedItem(InventoryGui gui) { if ((Object)(object)gui == (Object)null) { return null; } int num = -1; try { MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), "GetSelectedRecipeIndex", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo != null) { num = (int)methodInfo.Invoke(gui, new object[1] { false }); } } catch { num = -1; } if (num >= 0 && num < Items.Count && Items[num] != null) { return Items[num]; } ItemData result = null; if (CraftUpgradeItemField != null) { object? value = CraftUpgradeItemField.GetValue(gui); result = (ItemData)((value is ItemData) ? value : null); } return result; } public static bool TryBeginProgress(InventoryGui gui) { if (!Active || (Object)(object)gui == (Object)null || HasProgress) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } ItemData val = ResolveSelectedItem(gui); if (val == null) { return false; } val = ResolveLiveInventoryItem(((Humanoid)localPlayer).GetInventory(), val); if (val == null) { return false; } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if (!TryGetDismantleRecipe(localPlayer, currentCraftingStation, val, out var recipe)) { return false; } List<KeyValuePair<ItemDrop, int>> refund = BuildRefund(recipe, val.m_quality); if (!CanFitRefund(((Humanoid)localPlayer).GetInventory(), refund)) { ((Character)localPlayer).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false); return true; } _progressItem = val; _progressRecipe = recipe; if (CraftRecipeField != null) { CraftRecipeField.SetValue(gui, recipe); } if (CraftUpgradeItemField != null) { CraftUpgradeItemField.SetValue(gui, null); } if (CraftTimerField != null) { CraftTimerField.SetValue(gui, 0f); } TryInstantiateVibration(gui); PlayCraftEffects(gui, localPlayer, currentCraftingStation, done: false); return true; } public static void CancelProgress(InventoryGui gui) { _progressItem = null; _progressRecipe = null; if (!((Object)(object)gui == (Object)null)) { if (CraftRecipeField != null) { CraftRecipeField.SetValue(gui, null); } if (CraftTimerField != null) { CraftTimerField.SetValue(gui, -1f); } } } public static bool TryCompleteProgress(InventoryGui gui) { if (!Active || _progressItem == null || (Object)(object)_progressRecipe == (Object)null) { return false; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { CancelProgress(gui); return true; } ItemData progressItem = _progressItem; Recipe progressRecipe = _progressRecipe; int quality = progressItem?.m_quality ?? 1; _progressItem = null; _progressRecipe = null; if (CraftRecipeField != null) { CraftRecipeField.SetValue(gui, null); } if (CraftTimerField != null) { CraftTimerField.SetValue(gui, -1f); } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory == null || progressItem == null) { return true; } ItemData val = ResolveLiveInventoryItem(inventory, progressItem); if (val == null || !CanDismantle(localPlayer, currentCraftingStation, val)) { ((Character)localPlayer).Message((MessageType)2, "Dismantle failed", 0, (Sprite)null, false); return true; } int num = Mathf.Max(1, progressRecipe.m_amount); if (val.m_stack < num) { ((Character)localPlayer).Message((MessageType)2, "Dismantle failed", 0, (Sprite)null, false); return true; } List<KeyValuePair<ItemDrop, int>> list = BuildRefund(progressRecipe, quality); if (!CanFitRefund(inventory, list)) { ((Character)localPlayer).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false); return true; } int stack = val.m_stack; bool flag = ((num < val.m_stack) ? inventory.RemoveItem(val, num) : inventory.RemoveItem(val)); if (!flag) { flag = TryForceRemove(inventory, progressItem, num); } if (flag) { ItemData val2 = ResolveLiveInventoryItem(inventory, progressItem); if (val2 != null && val2.m_stack >= stack) { flag = false; } } if (!flag) { ((Character)localPlayer).Message((MessageType)2, "Dismantle failed", 0, (Sprite)null, false); if (Plugin.Log != null) { Plugin.Log.LogWarning((object)"Dismantle: could not remove selected item from inventory"); } return true; } for (int i = 0; i < list.Count; i++) { ItemDrop key = list[i].Key; int value = list[i].Value; if ((Object)(object)key == (Object)null || value <= 0) { continue; } string name = ((Object)key).name; if (string.IsNullOrEmpty(name)) { continue; } int num2 = value; while (num2 > 0) { int num3 = num2; try { int num4 = ((key.m_itemData?.m_shared != null) ? Mathf.Max(1, key.m_itemData.m_shared.m_maxStackSize) : num2); num3 = Mathf.Min(num2, num4); } catch { } if (inventory.AddItem(name, num3, 1, 0, 0L, "", false, false) == null && !inventory.AddItem(((Component)key).gameObject, num3)) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("Dismantle could not add " + name + " x" + num3)); } break; } num2 -= num3; } } PlayCraftEffects(gui, localPlayer, currentCraftingStation, done: true); ((Character)localPlayer).Message((MessageType)2, "Dismantled", 0, (Sprite)null, false); return true; } private static ItemData ResolveLiveInventoryItem(Inventory inv, ItemData snapshot) { if (inv == null || snapshot?.m_shared == null) { return null; } if (inv.ContainsItem(snapshot)) { return snapshot; } try { ItemData itemAt = inv.GetItemAt(snapshot.m_gridPos.x, snapshot.m_gridPos.y); if (itemAt != null && SameDismantleTarget(itemAt, snapshot)) { return itemAt; } } catch { } List<ItemData> allItems = inv.GetAllItems(); if (allItems == null) { return null; } for (int i = 0; i < allItems.Count; i++) { ItemData val = allItems[i]; if (SameDismantleTarget(val, snapshot)) { return val; } } return null; } private static bool SameDismantleTarget(ItemData a, ItemData b) { if (a?.m_shared == null || b?.m_shared == null) { return false; } if (a.m_equipped || b.m_equipped) { return false; } if (!string.Equals(a.m_shared.m_name, b.m_shared.m_name, StringComparison.Ordinal)) { return false; } if (a.m_quality != b.m_quality) { return false; } if (a.m_variant != b.m_variant) { return false; } return true; } private static bool TryForceRemove(Inventory inv, ItemData snapshot, int amount) { if (inv == null || snapshot?.m_shared == null || amount <= 0) { return false; } ItemData val = ResolveLiveInventoryItem(inv, snapshot); if (val == null) { return false; } if (amount >= val.m_stack) { return inv.RemoveItem(val); } return inv.RemoveItem(val, amount); } private static void TryInstantiateVibration(InventoryGui gui) { if ((Object)(object)gui == (Object)null || CraftingVibrationField == null) { return; } try { object? value = CraftingVibrationField.GetValue(gui); GameObject val = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val != (Object)null) { Object.Instantiate<GameObject>(val); } } catch { } } private static void PlayCraftEffects(InventoryGui gui, Player player, CraftingStation station, bool done) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return; } EffectList val = null; try { if ((Object)(object)station != (Object)null) { val = (done ? station.m_craftItemDoneEffects : station.m_craftItemEffects); } } catch { } if (val == null && (Object)(object)gui != (Object)null) { FieldInfo fieldInfo = (done ? CraftItemDoneEffectsField : CraftItemEffectsField); if (fieldInfo != null) { object? value = fieldInfo.GetValue(gui); val = (EffectList)((value is EffectList) ? value : null); } } if (val == null) { return; } try { val.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("Dismantle effects: " + ex.Message)); } } } private static bool CanFitRefund(Inventory inv, List<KeyValuePair<ItemDrop, int>> refund) { if (inv == null || refund == null || refund.Count == 0) { return true; } if (inv.GetEmptySlots() > 0) { return true; } for (int i = 0; i < refund.Count; i++) { ItemDrop key = refund[i].Key; if (key?.m_itemData?.m_shared == null) { return false; } SharedData shared = key.m_itemData.m_shared; if (inv.CountItems(shared.m_name, -1, true) <= 0 && shared.m_maxStackSize <= 1) { return false; } } return true; } } internal static class MaterialNameBucket { private static readonly string[] Tokens = new string[52] { "BlackMetal", "Blackmetal", "FineWood", "Finewood", "TrollLeather", "HardAntler", "Serpentscale", "Serpent", "Flametal", "Carapace", "Fenring", "Fenris", "Fenrir", "Vilebone", "VileBone", "Bronze", "Copper", "Silver", "Iron", "Flint", "Bone", "Leather", "Padded", "Antler", "Wood", "Root", "Ancient", "Abyssal", "Chitin", "Wolf", "Frost", "Crystal", "Obsidian", "Needle", "Eitr", "Mage", "Himmin", "Mist", "Dvergr", "Ashlands", "Asksvin", "Embla", "Blood", "Bile", "Ooze", "Fire", "Poison", "Banded", "Rags", "Rag", "Berserker", "Lox" }; private static readonly Dictionary<string, string> PrefabOverrides = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "HelmetDrake", "Wolf" }, { "TrinketSilverDamage", "Wolf" }, { "Bow", "Bows" }, { "BowFineWood", "Bows" }, { "BowHuntsman", "Bows" }, { "BowDraugrFang", "Bows" }, { "Battleaxe", "Iron" }, { "MaceNeedle", "Iron" }, { "BattleaxeWood", "Wood" }, { "Club", "Wood" }, { "SledgeStagbreaker", "Wood" }, { "AxeStone", "Stone" }, { "FistBjornClaw", "Bear" }, { "ShieldWood", "Shields" }, { "ShieldWoodTower", "Shields" }, { "ShieldBoneTower", "Shields" }, { "ShieldRoots", "Shields" }, { "BattleaxeBlackmetal", "BlackMetal" }, { "Battleaxe_Blackmetal", "BlackMetal" }, { "TrinketSilverResist", "Crystal" }, { "BattleaxeCrystal", "Crystal" }, { "Battleaxe_Crystal", "Crystal" }, { "HelmetBerserkerUndead", "Vilebone" }, { "ArmorBerserkerUndeadChest", "Vilebone" }, { "ArmorBerserkerUndeadLegs", "Vilebone" }, { "FistBjornUndeadClaw", "Vilebone" }, { "FistUnbjornClaw", "Vilebone" }, { "HelmetBerserker", "Berserker" }, { "ArmorBerserkerChest", "Berserker" }, { "ArmorBerserkerLegs", "Berserker" }, { "HelmetFenrir", "Fenrir" }, { "ArmorFenrirChest", "Fenrir" }, { "ArmorFenrirLegs", "Fenrir" }, { "HelmetLox", "Lox" }, { "ArmorLoxChest", "Lox" }, { "ArmorLoxLegs", "Lox" }, { "CapeLox", "Lox" }, { "SadleLox", "Lox" }, { "SaddleLox", "Lox" }, { "CapeDeerHide", "Cape" }, { "CapeLinen", "Cape" }, { "CapeOdin", "Cape" }, { "CapeTrollHide", "Cape" }, { "CapeWolf", "Cape" }, { "HelmetOdin", "Clothes" }, { "HelmetCelebration", "Clothes" }, { "HelmetFishingHat", "Clothes" }, { "HelmetMidsummerCrown", "Clothes" }, { "HelmetPointyHat", "Clothes" }, { "HelmetStrawhat", "Clothes" }, { "BombOoze", "Bomb" }, { "BombBile", "Bomb" }, { "BombBlob_Poison", "Bomb" }, { "BombBlob_PoisonElite", "Bomb" }, { "BombBlob_Frost", "Bomb" }, { "BombBlob_Lava", "Bomb" }, { "BombBlob_Morkhalla", "Bomb" }, { "BombBlob_Tar", "Bomb" }, { "BombDynamite", "Bomb" }, { "BombLava", "Bomb" }, { "BombSiege", "Bomb" }, { "BombSmoke", "Bomb" }, { "FireworksBlue", "Firework" }, { "FireworksCyan", "Firework" }, { "FireworksGreen", "Firework" }, { "FireworksPurple", "Firework" }, { "FireworksRed", "Firework" }, { "FireworksYellow", "Firework" }, { "PotionHealthMinor", "Potion" }, { "PotionStaminaMinor", "Potion" }, { "Tankard", "Skol" }, { "TankardAnniversary", "Skol" }, { "TankardOdin", "Skol" }, { "Snowball", "Misc" }, { "CatapultPayload_Grausten", "Misc" }, { "AxeEarly", "Special" }, { "Feaster", "Furniture" }, { "Adze", "Furniture" }, { "Chisel", "Tools" }, { "Torch", "Tools" }, { "StaffFireball", "Staffs" }, { "StaffIceShards", "Staffs" }, { "StaffLightning", "Staffs" }, { "StaffTroll", "Staffs" }, { "StaffSkeleton", "Staffs" }, { "StaffClusterbomb", "Staffs" }, { "StaffShield", "Staffs" }, { "StaffProtect", "Staffs" }, { "StaffProtection", "Staffs" }, { "StaffGreenRoots", "Staffs" }, { "StaffNature", "Staffs" }, { "StaffWild", "Staffs" } }; private static readonly Regex SpaceyBlackMetal = new Regex("black\\s*metal", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SpaceyFineWood = new Regex("fine\\s*wood", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SpaceyTrollLeather = new Regex("troll\\s*leather", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SpaceySerpent = new Regex("serpent\\s*scale", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SpaceyVileBone = new Regex("vile\\s*[_-]?\\s*bone", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static string Resolve(Recipe recipe) { if ((Object)(object)recipe == (Object)null) { return null; } if (WeaponSetDetector.IsAmmo(recipe)) { return "Arrows"; } string text = StripClone(PrefabName(recipe) ?? ""); if (!string.IsNullOrEmpty(text) && PrefabOverrides.TryGetValue(text, out var value)) { return value; } string text2 = FromPrefabFamily(text); if (!string.IsNullOrEmpty(text2)) { return text2; } if (text.StartsWith("Staff", StringComparison.OrdinalIgnoreCase)) { return "Staffs"; } string text3 = SharedName(recipe) ?? ""; string text4 = TryLocalize(text3); string text5 = text + " " + text3 + " " + text4; string text6 = TrySpecialBucket(text, text5, text4); if (!string.IsNullOrEmpty(text6)) { return text6; } if (IsVilebone(text5, text4, text)) { return "Vilebone"; } if (SpaceyVileBone.IsMatch(text5)) { return "Vilebone"; } if (SpaceyBlackMetal.IsMatch(text5) || ContainsAny(text5, "BlackMetal", "Blackmetal")) { return "BlackMetal"; } if (SpaceyFineWood.IsMatch(text5)) { return "FineWood"; } if (SpaceyTrollLeather.IsMatch(text5)) { return "TrollLeather"; } if (SpaceySerpent.IsMatch(text5)) { return "Serpentscale"; } for (int i = 0; i < Tokens.Length; i++) { string text7 = Tokens[i]; if (text5.IndexOf(text7, StringComparison.OrdinalIgnoreCase) >= 0) { if (text7.Equals("Bone", StringComparison.OrdinalIgnoreCase) && SpaceyVileBone.IsMatch(text5)) { return "Vilebone"; } if (text7.Equals("Fire", StringComparison.OrdinalIgnoreCase) && ContainsAny(text5, "Firework")) { return "Firework"; } return Canonical(text7); } } return null; } private static string FromPrefabFamily(string prefab) { if (string.IsNullOrEmpty(prefab)) { return null; } if (prefab.StartsWith("Shield", StringComparison.OrdinalIgnoreCase)) { return "Shields"; } if (prefab.StartsWith("Bomb", StringComparison.OrdinalIgnoreCase)) { return "Bomb"; } if (prefab.StartsWith("Fireworks", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("Firework", StringComparison.OrdinalIgnoreCase)) { return "Firework"; } if (prefab.StartsWith("Potion", StringComparison.OrdinalIgnoreCase)) { return "Potion"; } if (prefab.StartsWith("Tankard", StringComparison.OrdinalIgnoreCase)) { return "Skol"; } if (prefab.StartsWith("ArmorDress", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("ArmorTunic", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("ArmorHarvester", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("HelmetHat", StringComparison.OrdinalIgnoreCase)) { return "Clothes"; } if (ContainsAny(prefab, "BerserkerUndead")) { return "Vilebone"; } if (ContainsAny(prefab, "Berserker") && !ContainsAny(prefab, "Undead")) { return "Berserker"; } if (ContainsAny(prefab, "Fenrir")) { return "Fenrir"; } if (ContainsAny(prefab, "Lox") || prefab.Equals("SadleLox", StringComparison.OrdinalIgnoreCase)) { return "Lox"; } return null; } public static int NestedToolTier(Recipe recipe) { if ((Object)(object)recipe == (Object)null) { return 5000; } string text = StripClone(PrefabName(recipe) ?? ""); string text2 = SharedName(recipe) ?? ""; string text3 = text + " " + text2 + " " + TryLocalize(text2); if (SpaceyBlackMetal.IsMatch(text3) || ContainsAny(text3, "BlackMetal", "Blackmetal")) { return Tier("BlackMetal"); } if (SpaceyFineWood.IsMatch(text3)) { return Tier("FineWood"); } for (int i = 0; i < Tokens.Length; i++) { string text4 = Tokens[i]; if (text3.IndexOf(text4, StringComparison.OrdinalIgnoreCase) >= 0) { string text5 = Canonical(text4); if (!text5.Equals("Vilebone", StringComparison.OrdinalIgnoreCase)) { return Tier(text5); } } } if (ContainsAny(text, "Hammer", "Hoe", "Cultivator", "Torch", "Chisel") && !ContainsAny(text, "Iron", "Bronze", "Black")) { return Tier("Wood"); } return 5000; } private static string TrySpecialBucket(string prefab, string blob, string localized) { string blob2 = localized + " " + blob; if (IsVilebone(blob, localized, prefab)) { return "Vilebone"; } if (ContainsAny(blob2, "Wolf Sight", "Wolfsicht", "Wolfssicht")) { return "Wolf"; } if (ContainsAny(blob2, "Crystal Heart", "Crystal Hearth", "Kristallherz", "Kristallherd")) { return "Crystal"; } if (ContainsAny(blob2, "Porcupine", "Stachelschwein")) { return "Iron"; } if (ContainsAny(blob2, "Drake Helmet", "Drachenhelm") || prefab.Equals("HelmetDrake", StringComparison.OrdinalIgnoreCase)) { return "Wolf"; } if (ContainsAny(blob2, "Huntsman", "Jägerbogen", "Jaegerbogen") || ContainsAny(blob2, "Draugr Fang", "Draugrzahn")) { return "Bows"; } if (ContainsAny(blob2, "Battleaxe", "Streitaxt") && !ContainsAny(prefab, "Crystal", "Wood") && !ContainsAny(prefab, "BlackMetal", "Blackmetal") && !ContainsAny(blob2, "Black Metal", "Blackmetal", "Kristall", "Wood")) { return "Iron"; } if (ContainsAny(blob2, "Staff of", "Dead raiser", "Dead Raiser", "Dundr", "Trollstav", "Troll staff") || ContainsAny(prefab, "Staff")) { return "Staffs"; } if (ContainsAny(blob, "Pickaxe", "Cultivator", "Scythe", "ButcherKnife", "Butcher", "Torch", "Chisel") || prefab.Equals("Torch", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Hammer", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Hoe", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Chisel", StringComparison.OrdinalIgnoreCase)) { return "Tools"; } if (ContainsAny(blob, "Huntsman") || ContainsAny(blob, "DraugrFang", "Draugrfang") || (ContainsAny(blob, "Draugr") && ContainsAny(blob, "Fang") && ContainsAny(blob, "Bow")) || prefab.Equals("Bow", StringComparison.OrdinalIgnoreCase) || prefab.Equals("BowFineWood", StringComparison.OrdinalIgnoreCase)) { return "Bows"; } if (ContainsAny(blob, "Drake") && ContainsAny(blob, "Helmet", "Hood", "Hat")) { return "Wolf"; } if (ContainsAny(blob, "WolfSight", "Wolfsight") || (ContainsAny(blob, "Wolf") && ContainsAny(blob, "Sight"))) { return "Wolf"; } if (ContainsAny(blob, "CrystalHearth", "CrystalHeart", "Crystal_Hearth", "Crystal_Heart") || (ContainsAny(blob, "Crystal") && ContainsAny(blob, "Hearth", "Heart"))) { return "Crystal"; } if (prefab.Equals("Battleaxe", StringComparison.OrdinalIgnoreCase) || prefab.Equals("MaceNeedle", StringComparison.OrdinalIgnoreCase)) { return "Iron"; } if (prefab.Equals("BattleaxeWood", StringComparison.OrdinalIgnoreCase)) { return "Wood"; } if (prefab.Equals("Adze", StringComparison.OrdinalIgnoreCase) || prefab.Equals("Feaster", StringComparison.OrdinalIgnoreCase)) { return "Furniture"; } if (prefab.Equals("Snowball", StringComparison.OrdinalIgnoreCase)) { return "Misc"; } return null; } private static bool IsVilebone(string blob, string localized, string prefab) { string text = (prefab ?? "").ToLowerInvariant(); string text2 = (localized + " " + blob + " " + text).ToLowerInvariant(); if (text.IndexOf("berserkerundead", StringComparison.Ordinal) >= 0 || text.IndexOf("bjornundead", StringComparison.Ordinal) >= 0 || text.IndexOf("unbjorn", StringComparison.Ordinal) >= 0 || text.Equals("helmetberserkerundead", StringComparison.Ordinal) || text.Equals("armorberserkerundeadchest", StringComparison.Ordinal) || text.Equals("armorberserkerundeadlegs", StringComparison.Ordinal) || text.Equals("fistbjornundeadclaw", StringComparison.Ordinal) || text.Equals("fistunbjornclaw", StringComparison.Ordinal)) { return true; } if (SpaceyVileBone.IsMatch(text2) || text2.IndexOf("vilebone", StringComparison.Ordinal) >= 0 || text2.IndexOf("vile_bone", StringComparison.Ordinal) >= 0 || text2.IndexOf("vile-bone", StringComparison.Ordinal) >= 0) { return true; } if (text2.IndexOf("maulclaws", StringComparison.Ordinal) >= 0 || text2.IndexOf("maul claws", StringComparison.Ordinal) >= 0) { return true; } if (text2.IndexOf("vilebone cage", StringComparison.Ordinal) >= 0 || text2.IndexOf("vilebone visage", StringComparison.Ordinal) >= 0 || text2.IndexOf("vilebone drap", StringComparison.Ordinal) >= 0) { return true; } return false; } public static int Tier(string bucket) { if (string.IsNullOrEmpty(bucket)) { return 10000; } int num = SectionOf(bucket); int num2 = WithinSection(bucket); return num * 1000 + num2; } public static int SectionOf(string bucket) { if (string.IsNullOrEmpty(bucket)) { return 0; } if (bucket.Equals("Shields", StringComparison.OrdinalIgnoreCase)) { return 1; } if (bucket.Equals("Tools", StringComparison.OrdinalIgnoreCase)) { return 2; } if (IsArmorBucket(bucket)) { return 3; } if (bucket.Equals("Cape", StringComparison.OrdinalIgnoreCase)) { return 4; } if (bucket.Equals("Bomb", StringComparison.OrdinalIgnoreCase)) { return 5; } if (bucket.Equals("Firework", StringComparison.OrdinalIgnoreCase)) { return 6; } if (bucket.Equals("Skol", StringComparison.OrdinalIgnoreCase)) { return 7; } if (bucket.Equals("Mist", StringComparison.OrdinalIgnoreCase)) { return 8; } if (bucket.Equals("Potion", StringComparison.OrdinalIgnoreCase) || bucket.Equals("Furniture", StringComparison.OrdinalIgnoreCase) || bucket.Equals("Misc", StringComparison.OrdinalIgnoreCase)) { return 9; } return 0; } private static bool IsArmorBucket(string bucket) { if (!bucket.Equals("Rags", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Leather", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("TrollLeather", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Root", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Berserker", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Fenrir", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Fenring", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Lox", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Clothes", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Wolf", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Vilebone", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Padded", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Carapace", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Mage", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Eitr", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Ashlands", StringComparison.OrdinalIgnoreCase) && !bucket.Equals("Asksvin", StringComparison.OrdinalIgnoreCase)) { return bucket.Equals("Embla", StringComparison.OrdinalIgnoreCase); } return true; } private static int WithinSection(string bucket) { if (bucket.Equals("Arrows", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Bows", StringComparison.OrdinalIgnoreCase)) { return 1; } if (bucket.Equals("Stone", StringComparison.OrdinalIgnoreCase)) { return 2; } if (bucket.Equals("Wood", StringComparison.OrdinalIgnoreCase)) { return 3; } if (bucket.Equals("Flint", StringComparison.OrdinalIgnoreCase)) { return 4; } if (bucket.Equals("Chitin", StringComparison.OrdinalIgnoreCase)) { return 5; } if (bucket.Equals("Special", StringComparison.OrdinalIgnoreCase)) { return 6; } if (bucket.Equals("Bear", StringComparison.OrdinalIgnoreCase)) { return 7; } if (bucket.Equals("Staffs", StringComparison.OrdinalIgnoreCase)) { return 80; } if (bucket.Equals("Shields", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Tools", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Rags", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Leather", StringComparison.OrdinalIgnoreCase)) { return 1; } if (bucket.Equals("TrollLeather", StringComparison.OrdinalIgnoreCase)) { return 2; } if (bucket.Equals("Root", StringComparison.OrdinalIgnoreCase)) { return 3; } if (bucket.Equals("Berserker", StringComparison.OrdinalIgnoreCase)) { return 4; } if (bucket.Equals("Fenrir", StringComparison.OrdinalIgnoreCase) || bucket.Equals("Fenring", StringComparison.OrdinalIgnoreCase)) { return 5; } if (bucket.Equals("Lox", StringComparison.OrdinalIgnoreCase)) { return 6; } if (bucket.Equals("Wolf", StringComparison.OrdinalIgnoreCase)) { return 7; } if (bucket.Equals("Vilebone", StringComparison.OrdinalIgnoreCase)) { return 8; } if (bucket.Equals("Clothes", StringComparison.OrdinalIgnoreCase)) { return 9; } if (bucket.Equals("Cape", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Bomb", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Firework", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Skol", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Mist", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Potion", StringComparison.OrdinalIgnoreCase)) { return 0; } if (bucket.Equals("Furniture", StringComparison.OrdinalIgnoreCase)) { return 1; } if (bucket.Equals("Misc", StringComparison.OrdinalIgnoreCase)) { return 2; } return 100 + MaterialProgression.Tier("Weapon" + bucket); } public static string Label(string bucket) { if (string.IsNullOrEmpty(bucket)) { return null; } if (bucket.Equals("Arrows", StringComparison.OrdinalIgnoreCase) || bucket.Equals("Ammo", StringComparison.OrdinalIgnoreCase)) { return "Arrows"; } if (bucket.Equals("Tools", StringComparison.OrdinalIgnoreCase)) { return "Tools"; } if (bucket.Equals("Bows", StringComparison.OrdinalIgnoreCase)) { return "Bows"; } if (bucket.Equals("Staffs", StringComparison.OrdinalIgnoreCase)) { return "Staffs"; } if (bucket.Equals("Shields", StringComparison.OrdinalIgnoreCase)) { return "Shields"; } if (bucket.Equals("Vilebone", StringComparison.OrdinalIgnoreCase)) { return "Vilebone"; } if (bucket.Equals("Bomb", StringComparison.OrdinalIgnoreCase)) { return "Bomb"; } if (bucket.Equals("Firework", StringComparison.OrdinalIgnoreCase)) { return "Firework"; } if (bucket.Equals("Potion", StringComparison.OrdinalIgnoreCase)) { return "Potion"; } if (bucket.Equals("Skol", StringComparison.OrdinalIgnoreCase)) { return "Skol"; } if (bucket.Equals("Cape", StringComparison.OrdinalIgnoreCase)) { return "Cape"; } if (bucket.Equals("Clothes", StringComparison.OrdinalIgnoreCase)) { return "Clothes"; } if (bucket.Equals("Furniture", StringComparison.OrdinalIgnoreCase)) { return "Furniture"; } if (bucket.Equals("Misc", StringComparison.OrdinalIgnoreCase)) { return "Misc"; } if (bucket.Equals("Special", StringComparison.OrdinalIgnoreCase)) { return "Special"; } if (bucket.Equals("Stone", StringComparison.OrdinalIgnoreCase)) { return "Stone"; } if (bucket.Equals("Bear", StringComparison.OrdinalIgnoreCase)) { return "Bear"; } if (bucket.Equals("Berserker", StringComparison.OrdinalIgnoreCase)) { return "Berserker"; } if (bucket.Equals("Fenrir", StringComparison.OrdinalIgnoreCase)) { return "Fenrir"; } if (bucket.Equals("Lox", StringComparison.OrdinalIgnoreCase)) { return "Lox"; } return ToSentenceCase(SplitCamel(Canonical(bucket))); } private static string StripClone(string name) { if (string.IsNullOrEmpty(name)) { return name; } if (name.EndsWith("(Clone)", StringComparison.OrdinalIgnoreCase)) { return name.Substring(0, name.Length - "(Clone)".Length).Trim(); } return name; } private static string TryLocalize(string token) { if (string.IsNullOrEmpty(token)) { return ""; } try { Type type = Type.GetType("Localization, assembly_valheim") ?? Type.GetType("Localization"); if (type == null) { return token; } PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public); object obj = ((property != null) ? property.GetValue(null, null) : null); if (obj == null) { return token; } MethodInfo method = type.GetMethod("Localize", new Type[1] { typeof(string) }); if (method == null) { return token; } return (method.Invoke(obj, new object[1] { token }) as string) ?? token; } catch { return token; } } private static bool ContainsAny(string blob, params string[] needles) { if (string.IsNullOrEmpty(blob) || needles == null) { return false; } for (int i = 0; i < needles.Length; i++) { if (!string.IsNullOrEmpty(needles[i]) && blob.IndexOf(needles[i], StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static string ToSentenceCase(string s) { if (string.IsNullOrEmpty(s)) { return s; } s = s.Trim().ToLowerInvariant(); if (s.Length == 0) { return s; } return char.ToUpperInvariant(s[0]) + s.Substring(1); } private static string Canonical(string tok) { if (tok.Equals("Blackmetal", StringComparison.OrdinalIgnoreCase)) { return "BlackMetal"; } if (tok.Equals("Finewood", StringComparison.OrdinalIgnoreCase)) { return "FineWood"; } if (tok.Equals("Banded", StringComparison.OrdinalIgnoreCase)) { return "Bronze"; } if (tok.Equals("Serpent", StringComparison.OrdinalIgnoreCase)) { return "Serpentscale"; } if (tok.Equals("Rag", StringComparison.OrdinalIgnoreCase)) { return "Rags"; } if (tok.Equals("Fenris", StringComparison.OrdinalIgnoreCase) || tok.Equals("Fenring", StringComparison.OrdinalIgnoreCase)) { return "Fenrir"; } if (tok.Equals("VileBone", StringComparison.OrdinalIgnoreCase) || tok.Equals("Vilebone", StringComparison.OrdinalIgnoreCase)) { return "Vilebone"; } if (tok.Length > 0 && char.IsLower(tok[0])) { return char.ToUpperInvariant(tok[0]) + tok.Substring(1); } return tok; } private static string SplitCamel(string s) { if (string.IsNullOrEmpty(s)) { return s; } StringBuilder stringBuilder = new StringBuilder(s.Length + 4); for (int i = 0; i < s.Length; i++) { char c = s[i]; if (i > 0 && char.IsUpper(c) && char.IsLower(s[i - 1])) { stringBuilder.Append(' '); } stringBuilder.Append(c); } return stringBuilder.ToString(); } private static string PrefabName(Recipe recipe) { if ((Object)(object)recipe?.m_item == (Object)null) { return null; } string name = ((Object)recipe.m_item).name; if (!string.IsNullOrEmpty(name)) { return name; } if (!((Object)(object)((Component)recipe.m_item).gameObject != (Object)null)) { return null; } return ((Object)((Component)recipe.m_item).gameObject).name; } private static string SharedName(Recipe recipe) { try { return recipe?.m_item?.m_itemData?.m_shared?.m_name; } catch { return null; } } } internal static class MaterialProgression { private static readonly string[] TierOrder = new string[64] { "Wood", "FineWood", "Flint", "Stone", "Bone", "Rags", "Rag", "Leather", "Copper", "TrollLeather", "Troll", "Bronze", "Banded", "HardAntler", "Antler", "Iron", "Root", "Ancient", "Abyssal", "Chitin", "Serpentscale", "Serpent", "Silver", "Wolf", "Fenrir", "Fenring", "Fenris", "Frost", "Crystal", "Obsidian", "Drake", "Lox", "Berserker", "Bear", "BlackMetal", "Padded", "Needle", "Fang", "Porcupine", "Carapace", "Eitr", "Mage", "Himmin", "Mist", "Dvergr", "Vilebone", "Flametal", "Ashlands", "Asksvin", "Embla", "Blood", "Bile", "Ooze", "Fire", "Poison", "Bomb", "Firework", "Potion", "Skol", "Cape", "Clothes", "Furniture", "Misc", "Special" }; private static readonly Dictionary<string, int> IndexByMaterial = BuildIndex(); public static int Tier(string setKey) { if (string.IsNullOrEmpty(setKey)) { return 10000; } string text = MaterialName(setKey); if (string.IsNullOrEmpty(text)) { return 9000; } if (IndexByMaterial.TryGetValue(text, out var value)) { return value; } for (int i = 0; i < TierOrder.Length; i++) { if (text.IndexOf(TierOrder[i], StringComparison.OrdinalIgnoreCase) >= 0 || TierOrder[i].IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { return i; } } return 8000; } public static string MaterialName(string setKey) { return StripPrefix(setKey); } private static string StripPrefix(string setKey) { string text = setKey; if (text.StartsWith("Weapon", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Weapon".Length); } else if (text.StartsWith("Tool", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Tool".Length); } else if (text.StartsWith("Shield", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Shield".Length); } else if (text.StartsWith("Armor", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Armor".Length); } else if (text.StartsWith("Cape", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Cape".Length); } else if (text.StartsWith("Helmet", StringComparison.OrdinalIgnoreCase)) { text = text.Substring("Helmet".Length); } return text; } private static Dictionary<string, int> BuildIndex() { Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < TierOrder.Length; i++) { string key = TierOrder[i]; if (!dictionary.ContainsKey(key)) { dictionary[key] = i; } } dictionary["Blackmetal"] = (dictionary.ContainsKey("BlackMetal") ? dictionary["BlackMetal"] : 0); dictionary["Finewood"] = (dictionary.ContainsKey("FineWood") ? dictionary["FineWood"] : 0); return dictionary; } } internal enum CraftCategory { All, Weapons, Armor, Shields, Tools, Building, Furniture, Food, Potions, Materials, Misc } internal static class RecipeCategories { public static readonly CraftCategory[] Order = new CraftCategory[11] { CraftCategory.All, CraftCategory.Weapons, CraftCategory.Armor, CraftCategory.Shields, CraftCategory.Tools, CraftCategory.Building, CraftCategory.Furniture, CraftCategory.Food, CraftCategory.Potions, CraftCategory.Materials, CraftCategory.Misc }; public static string Label(CraftCategory cat) { return cat switch { CraftCategory.All => "All", CraftCategory.Weapons => "Weapons", CraftCategory.Armor => "Armor", CraftCategory.Shields => "Shields", CraftCategory.Tools => "Tools", CraftCategory.Building => "Building", CraftCategory.Furniture => "Furniture", CraftCategory.Food => "Food", CraftCategory.Potions => "Potions", CraftCategory.Materials => "Materials", _ => "Misc", }; } public static string ShortLabel(CraftCategory cat) { return Label(cat); } public static CraftCategory Classify(Recipe recipe) { //IL_003b: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Invalid comparison between Unknown and I4 //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Invalid comparison between Unknown and I4 //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Invalid comparison between Unknown and I4 //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Invalid comparison between Unknown and I4 //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Invalid comparison between Unknown and I4 //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Invalid comparison between Unknown and I4 //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Invalid comparison between Unknown and I4 //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Invalid comparison between Unknown and I4 //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Invalid comparison between Unknown and I4 //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Invalid comparison between Unknown and I4 //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Invalid comparison between Unknown and I4 //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Invalid comparison between Unknown and I4 //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Invalid comparison between Unknown and I4 if (recipe?.m_item?.m_itemData?.m_shared == null) { return CraftCategory.Misc; } SharedData shared = recipe.m_item.m_itemData.m_shared; ItemType itemType = shared.m_itemType; string text = ((Object)recipe.m_item).name ?? ""; string text2 = (((Object)(object)recipe.m_craftingStation != (Object)null) ? ((Object)recipe.m_craftingStation).name : ""); if ((int)itemType == 5) { return CraftCategory.Shields; } if (LooksToolPrefab(text)) { return CraftCategory.Tools; } if ((int)itemType == 3 || (int)itemType == 14 || (int)itemType == 4 || (int)itemType == 20 || (int)itemType == 15) { return CraftCategory.Weapons; } if ((int)itemType == 6 || (int)itemType == 7 || (int)itemType == 11 || (int)itemType == 17 || (int)itemType == 18) { if (text.IndexOf("Tool", StringComparison.OrdinalIgnoreCase) >= 0) { return CraftCategory.Tools; } return CraftCategory.Armor; } if ((int)itemType == 19) { return CraftCategory.Tools; } if ((int)itemType == 2) { if (IsPotionLike(text, shared.m_name)) { return CraftCategory.Potions; } return CraftCategory.Food; } if ((int)itemType == 1) { return CraftCategory.Materials; } if ((int)itemType == 9 || (int)itemType == 23) { return CraftCategory.Weapons; } if (text2.IndexOf("piece_workbench", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("Workbench", StringComparison.OrdinalIgnoreCase) >= 0) { if (LooksFurniture(text)) { return CraftCategory.Furniture; } if (LooksBuilding(text)) { return CraftCategory.Building; } } if (LooksFurniture(text)) { return CraftCategory.Furniture; } if (LooksBuilding(text)) { return CraftCategory.Building; } return CraftCategory.Misc; } public static bool Matches(Recipe recipe, CraftCategory filter) { if (filter == CraftCategory.All) { return true; } return Classify(recipe) == filter; } private static bool LooksToolPrefab(string prefab) { string text = prefab ?? ""; if (text.IndexOf("Pickaxe", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Hammer", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Hoe", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Cultivator", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("Scythe", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool IsPotionLike(string prefab, string sharedName) { string text = prefab + " " + sharedName; if (text.IndexOf("Mead", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Potion", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Flask", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Brew", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Tonic", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("Poison", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("Bait", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool LooksFurniture(string prefab) { string text = prefab ?? ""; if (text.IndexOf("chair", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("table", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("bed", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("rug", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("banner", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("candle", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("torch", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("sign", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("chest", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("itemstand", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("armorstand", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } private static bool LooksBuilding(string prefab) { string text = prefab ?? ""; if (text.IndexOf("wood_", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("stone_", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("darkwood_", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("piece_", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("wall", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("floor", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("roof", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("beam", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("pole", StringComparison.OrdinalIgnoreCase) < 0 && text.IndexOf("stair", StringComparison.OrdinalIgnoreCase) < 0) { return text.IndexOf("door", StringComparison.OrdinalIgnoreCase) >= 0; } return true; } } internal static class RecipeSort { private struct Entry { public Recipe Recipe; public int OriginalIndex; public int AmmoFirst; public int CraftBucket; public int MaterialPct; public int StationLevel; public int CategoryOrder; public string SetKey; public string MaterialBucket; public int PieceOrder; public string SortName; } private static readonly FieldInfo AvailableRecipesField = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes"); private static readonly FieldInfo RecipeListSpaceField = AccessTools.Field(typeof(InventoryGui), "m_recipeListSpace"); private static PropertyInfo _recipeProp; private static PropertyInfo _elementProp; private static bool _propsResolved; public static void Apply(List<Recipe> recipes) { if (recipes == null || Plugin.Settings == null || !Plugin.Settings.EnableMod.Value) { return; } if (!DismantleMode.Active) { StationFilter.Apply(recipes); if (Plugin.Settings.EnableCategories.Value) { CategoryBar.SyncAvailable(recipes); } if (recipes.Count == 0) { return; } if (Plugin.Settings.EnableCategories.Value && CategoryBar.Active != CraftCategory.All) { for (int num = recipes.Count - 1; num >= 0; num--) { if (!RecipeCategories.Matches(recipes[num], CategoryBar.Active)) { recipes.RemoveAt(num); } } } } if (recipes.Count != 0) { if (DismantleMode.Active) { DismantleMode.SortPaired(recipes); } else { SortInPlace(recipes); } } } public static void ReorderGui(InventoryGui gui) { if ((Object)(object)gui == (Object)null || Plugin.Settings == null || !Plugin.Settings.EnableMod.Value) { MaterialSectionHeaders.Clear(); } else if (Plugin.Settings.IsVanillaOrder()) { MaterialSectionHeaders.Clear(); } else if (DismantleMode.Active) { MaterialSectionHeaders.Clear(); } else { if (AvailableRecipesField == null) { return; } if (AvailableRecipesField.GetValue(gui) is IList { Count: not 0 } list) { List<Recipe> list2 = new List<Recipe>(list.Count); List<object> list3 = new List<object>(list.Count); List<GameObject> list4 = new List<GameObject>(list.Count); for (int i = 0; i < list.Count; i++) { object obj = list[i]; Recipe item = ReadRecipe(obj); list2.Add(item); list3.Add(obj); list4.Add(ReadElement(obj)); } List<int> list5 = new List<int>(list2.Count); for (int j = 0; j < list2.Count; j++) { list5.Add(j); } List<Entry> entries = BuildEntries(list2); bool groupArmor = Plugin.Settings.EnableArmorSetGrouping.Value || Plugin.Settings.EnableWeaponSetGrouping.Value || Plugin.Settings.EnableToolSetGrouping.Value || Plugin.Settings.EnableShieldSetGrouping.Value; bool craftBuckets = Plugin.Settings.UseCraftBuckets(); bool alphabetical = Plugin.Settings.IsAlphabetical(); bool progression = Plugin.Settings.IsProgression(); bool categoryThen = Plugin.Settings.IsCategoryThenCraftable(); list5.Sort((int ia, int ib) => Compare(entries[ia], entries[ib], groupArmor, craftBuckets, alphabetical, progression, categoryThen)); float rowSpace = 30f; if (RecipeListSpaceField != null && RecipeListSpaceField.GetValue(gui) is float num && num > 0.01f) { rowSpace = num; } list.Clear(); List<Recipe> list6 = new List<Recipe>(list5.Count); List<GameObject> list7 = new List<GameObject>(list5.Count); Transform val = null; for (int num2 = 0; num2 < list5.Count; num2++) { int index = list5[num2]; object value = list3[index]; list.Add(value); list6.Add(list2[index]); GameObject val2 = list4[index]; list7.Add(val2); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.transform.parent; } } MaterialSectionHeaders.Apply(val, list6, list7, rowSpace); if (Plugin.Settings.DebugLogging.Value) { Plugin.Log.LogInfo((object)("ReorderGui rows=" + list.Count + " space=" + rowSpace)); int num3 = Math.Min(12, list5.Count); for (int num4 = 0; num4 < num3; num4++) { Entry entry = entries[list5[num4]]; Plugin.Log.LogInfo((object)(" #" + num4 + " set=" + (entry.SetKey ?? "-") + " bucket=" + (entry.MaterialBucket ?? "-") + " ammo=" + entry.AmmoFirst + " tier=" + MaterialNameBucket.Tier(entry.MaterialBucket) + " bucketCraft=" + entry.CraftBucket + " piece=" + entry.PieceOrder + " name=" + entry.SortName)); } } } else { MaterialSectionHeaders.Clear(); } } } private static void SortInPlace(List<Recipe> recipes) { if (recipes.Count > 1 && !Plugin.Settings.IsVanillaOrder()) { List<Entry> list = BuildEntries(recipes); bool groupArmor = Plugin.Settings.EnableArmorSetGrouping.Value || Plugin.Settings.EnableWeaponSetGrouping.Value || Plugin.Settings.EnableToolSetGrouping.Value || Plugin.Settings.EnableShieldSetGrouping.Value; bool craftBuckets = Plugin.Settings.UseCraftBuckets(); bool alphabetical = Plugin.Settings.IsAlphabetical(); bool progression = Plugin.Settings.IsProgression(); bool categoryThen = Plugin.Settings.IsCategoryThenCraftable(); list.Sort((Entry a, Entry b) => Compare(a, b, groupArmor, craftBuckets, alphabetical, progression, categoryThen)); recipes.Clear(); for (int num = 0; num < list.Count; num++) { recipes.Add(list[num].Recipe); } } } private static List<Entry> BuildEntries(List<Recipe> recipes) { Player localPlayer = Player.m_localPlayer; string[] orderTokens = ArmorSetDetector.ParseOrder(Plugin.Settings.ArmorPieceOrder.Value); string[] orderTokens2 = WeaponSetDetector.ParseOrder(Plugin.Settings.WeaponPieceOrder.Value); string[] orderTokens3 = ToolSetDetector.ParseOrder(Plugin.Settings.ToolPieceOrder.Value); string[] orderTokens4 = ShieldSetDetector.ParseOrder(Plugin.Settings.ShieldPieceOrder.Value); bool value = Plugin.Settings.EnableArmorSetGrouping.Value; bool value2 = Plugin.Settings.EnableWeaponSetGrouping.Value; bool value3 = Plugin.Settings.EnableToolSetGrouping.Value; bool value4 = Plugin.Settings.EnableShieldSetGrouping.Value; bool value5 = Plugin.Settings.GroupModdedArmorSets.Value; bool value6 = Plugin.Settings.GroupModdedWeaponSets.Value; bool flag = Plugin.Settings.UseCraftBuckets(); bool flag2 = Plugin.Settings.IsCategoryThenCraftable(); List<Entry> list = new List<Entry>(recipes.Count); for (int i = 0; i < recipes.Count; i++) { Recipe val = recipes[i]; string text = null; int pieceOrder = 0; if (value) { text = ArmorSetDetector.SetKey(val, value5); if (!string.IsNullOrEmpty(text)) { pieceOrder = ArmorSetDetector.PieceOrder(val, orderTokens); } } if (string.IsNullOrEmpty(text) && value2) { if (WeaponSetDetector.IsAmmo(val)) { text = "WeaponAmmo"; pieceOrder = WeaponSetDetector.PieceOrder(val, orderTokens2); } else { text = WeaponSetDetector.SetKey(val, value6); if (!string.IsNullOrEmpty(text)) { pieceOrder = WeaponSetDetector.PieceOrder(val, orderTokens2); } } } if (string.IsNullOrEmpty(text) && value3) { text = ToolSetDetector.SetKey(val, value6); if (!string.IsNullOrEmpty(text)) { pieceOrder = ToolSetDetector.PieceOrder(val, orderTokens3); } } if (string.IsNullOrEmpty(text) && value4) { text = ShieldSetDetector.SetKey(val, value6); if (!string.IsNullOrEmpty(text)) { pieceOrder = ShieldSetDetector.PieceOrder(val, orderTokens4); } } list.Add(new Entry { Recipe = val, OriginalIndex = i, AmmoFirst = ((!WeaponSetDetector.IsAmmo(val)) ? 1 : 0), CraftBucket = (flag ? Craftability.ScoreBucket(localPlayer, val) : 0), MaterialPct = (flag ? Craftability.MaterialPercent(localPlayer, val) : 0), StationLevel = (((Object)(object)val != (Object)null) ? val.m_minStationLevel : 0), CategoryOrder = (int)(flag2 ? RecipeCategories.Classify(val) : CraftCategory.All), SetKey = text, MaterialBucket = MaterialNameBucket.Resolve(val), PieceOrder = pieceOrder, SortName = DisplayName(val) }); } return list; } private static int Compare(Entry a, Entry b, bool groupArmor, bool craftBuckets, bool alphabetical, bool progression, bool categoryThen) { if (categoryThen) { int num = a.CategoryOrder.CompareTo(b.CategoryOrder); if (num != 0) { return num; } } if (Plugin.Settings != null && (Plugin.Settings.EnableMaterialSectionHeaders.Value || Plugin.Settings.EnableWeaponSetGrouping.Value || Plugin.Settings.EnableArmorSetGrouping.Value || Plugin.Settings.EnableToolSetGrouping.Value || Plugin.Settings.EnableShieldSetGrouping.Value)) { int num2 = CompareNameBuckets(a, b, craftBuckets); if (num2 != 0) { return num2; } } else { if (craftBuckets) { int num3 = a.CraftBucket.CompareTo(b.CraftBucket); if (num3 != 0) { return num3; } } if (groupArmor) { int num4 = a.AmmoFirst.CompareTo(b.AmmoFirst); if (num4 != 0) { return num4; } } bool flag = groupArmor && !string.IsNullOrEmpty(a.SetKey); bool flag2 = groupArmor && !string.IsNullOrEmpty(b.SetKey); if (flag && flag2) { int num5 = CompareMaterialThenPiece(a, b); if (num5 != 0) { return num5; } } else if (groupArmor && (flag || flag2)) { if (flag) { return -1; } return 1; } } if (craftBuckets) { int num6 = b.MaterialPct.CompareTo(a.MaterialPct); if (num6 != 0) { return num6; } } if (progression) { int num7 = a.StationLevel.CompareTo(b.StationLevel); if (num7 != 0) { return num7; } } int num8 = string.Compare(a.SortName, b.SortName, StringComparison.OrdinalIgnoreCase); if (num8 != 0) { return num8; } return a.OriginalIndex.CompareTo(b.OriginalIndex); } private static int CompareNameBuckets(Entry a, Entry b, bool craftBuckets) { if (craftBuckets) { int num = a.CraftBucket.CompareTo(b.CraftBucket); if (num != 0) { return num; } } bool flag = !string.IsNullOrEmpty(a.MaterialBucket); bool flag2 = !string.IsNullOrEmpty(b.MaterialBucket); if (flag != flag2) { if (!flag) { return 1; } return -1; } if (!flag) { return 0; } if (!string.Equals(a.MaterialBucket, b.MaterialBucket, StringComparison.OrdinalIgnoreCase)) { int num2 = MaterialNameBucket.Tier(a.MaterialBucket); int value = MaterialNameBucket.Tier(b.MaterialBucket); int num3 = num2.CompareTo(value); if (num3 != 0) { return num3; } return string.Compare(a.MaterialBucket, b.MaterialBucket, StringComparison.OrdinalIgnoreCase); } if (a.MaterialBucket.Equals("Tools", StringComparison.OrdinalIgnoreCase)) { int num4 = MaterialNameBucket.NestedToolTier(a.Recipe); int value2 = MaterialNameBucket.NestedToolTier(b.Recipe); int num5 = num4.CompareTo(value2); if (num5 != 0) { return num5; } } int num6 = MaterialKind(a.SetKey).CompareTo(MaterialKind(b.SetKey)); if (num6 != 0) { return num6; } int num7 = a.PieceOrder.CompareTo(b.PieceOrder); if (num7 != 0) { return num7; } return string.Compare(a.SortName, b.SortName, StringComparison.OrdinalIgnoreCase); } private static int CompareMaterialThenPiece(Entry a, Entry b) { string text = MaterialProgression.MaterialName(a.SetKey); string text2 = MaterialProgression.MaterialName(b.SetKey); if (string.Equals(text, text2, StringComparison.OrdinalIgnoreCase)) { int num = MaterialKind(a.SetKey).CompareTo(MaterialKind(b.SetKey)); if (num != 0) { return num; } int num2 = a.PieceOrder.CompareTo(b.PieceOrder); if (num2 != 0) { return num2; } return string.Compare(a.SortName, b.SortName, StringComparison.OrdinalIgnoreCase); } int num3 = MaterialProgression.Tier(a.SetKey); int value = MaterialProgression.Tier(b.SetKey); int num4 = num3.CompareTo(value); if (num4 != 0) { return num4; } return string.Compare(text, text2, StringComparison.OrdinalIgnoreCase); } private static int MaterialKind(string setKey) { if (string.IsNullOrEmpty(setKey)) { return 50; } if (setKey.Equals("WeaponAmmo", StringComparison.OrdinalIgnoreCase)) { return 0; } if (setKey.StartsWith("Weapon", StringComparison.OrdinalIgnoreCase)) { return 1; } if (setKey.StartsWith("Shield", StringComparison.OrdinalIgnoreCase)) { return 2; } if (setKey.StartsWith("Tool", StringComparison.OrdinalIgnoreCase)) { return 3; } if (setKey.StartsWith("Armor", StringComparison.OrdinalIgnoreCase) || setKey.StartsWith("Cape", StringComparison.OrdinalIgnoreCase) || setKey.StartsWith("Helmet", StringComparison.OrdinalIgnoreCase)) { return 4; } return 40; } private static string DisplayName(Recipe recipe) { try { if (recipe?.m_item?.m_itemData?.m_shared != null) { return recipe.m_item.m_itemData.m_shared.m_name ?? ""; } } catch { } if (!((Object)(object)recipe?.m_item != (Object)null)) { return ""; } return ((Object)recipe.m_item).name; } private static void EnsurePairProps(object sample) { if (!_propsResolved && sample != null) { Type type = sample.GetType(); _recipeProp = AccessTools.Property(type, "Recipe"); _elementProp = AccessTools.Property(type, "InterfaceElement"); _propsResolved = true; } } private static Recipe ReadRecipe(object pair) { if (pair == null) { return null; } EnsurePairProps(pair); if (_recipeProp != null) { object? value = _recipeProp.GetValue(pair, null); return (Recipe)((value is Recipe) ? value : null); } FieldInfo fieldInfo = AccessTools.Field(pair.GetType(), "<Recipe>k__BackingField"); if (!(fieldInfo != null)) { return null; } object? value2 = fieldInfo.GetValue(pair); return (Recipe)((value2 is Recipe) ? value2 : null); } private static GameObject ReadElement(object pair) { if (pair == null) { return null; } EnsurePairProps(pair); object obj = null; if (_elementProp != null) { obj = _elementProp.GetValue(pair, null); } else { FieldInfo fieldInfo = AccessTools.Field(pair.GetType(), "<InterfaceElement>k__BackingField"); if (fieldInfo != null) { obj = fieldInfo.GetValue(pair); } } GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val != null) { return val; } Component val2 = (Component)((obj is Component) ? obj : null); if (val2 != null) { return val2.gameObject; } return null; } } internal static class ShieldSetDetector { private static readonly string[] MaterialStems = new string[20] { "BlackMetal", "Flametal", "Carapace", "Serpentscale", "Serpent", "Crystal", "Bronze", "Copper", "Silver", "Iron", "Banded", "Bone", "Chitin", "Abyssal", "FineWood", "Wood", "Ancient", "Ashlands", "Asksvin", "Flametal" }; private static readonly string[] ShieldTypeTokens = new string[2] { "TowerShield", "Shield" }; private static readonly Regex SharedCleanup = new Regex("^\\$?(item[_-]?)?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedShieldTrim = new Regex("[_-]?(towershield|shield)$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedShieldPrefix = new Regex("^(towershield|shield)[_-]", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static string SetKey(Recipe recipe, bool groupModded) { if ((Object)(object)recipe == (Object)null || !IsShield(recipe)) { return null; } string text = PrefabName(recipe) ?? ""; string text2 = SharedName(recipe) ?? ""; string blob = (text + " " + text2).Trim(); string text3 = FromPrefab(text); if (string.IsNullOrEmpty(text3)) { text3 = FromShared(text2); } if (string.IsNullOrEmpty(text3)) { text3 = FromKnownStem(blob); } if (string.IsNullOrEmpty(text3) || text3.Length < 3) { return null; } text3 = CanonicalizeMaterial(text3); if (string.IsNullOrEmpty(text3)) { return null; } if (text3.Equals("Banded", StringComparison.OrdinalIgnoreCase)) { text3 = "Bronze"; } if (!groupModded && !IsKnownMaterial(text3) && !LooksVanillaShieldPrefab(text)) { return null; } return "Shield" + text3; } public static int PieceOrder(Recipe recipe, string[] orderTokens) { string obj = PrefabName(recipe) ?? ""; string text = SharedName(recipe) ?? ""; string text2 = obj + " " + text; for (int i = 0; i < orderTokens.Length; i++) { string text3 = orderTokens[i]; if (!string.IsNullOrEmpty(text3) && !text3.Equals("Other", StringComparison.OrdinalIgnoreCase) && text2.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0) { return i; } } if (text2.IndexOf("Tower", StringComparison.OrdinalIgnoreCase) >= 0) { if (IndexOf(orderTokens, "Tower") >= orderTokens.Length) { return orderTokens.Length + 5; } return IndexOf(orderTokens, "Tower"); } return IndexOf(orderTokens, "Shield"); } public static string[] ParseOrder(string csv) { if (string.IsNullOrEmpty(csv)) { return DefaultOrder(); } string[] array = csv.Split(new char[1] { ',' }); List<string> list = new List<string>(); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } if (list.Count == 0) { return DefaultOrder(); } return list.ToArray(); } public static bool IsShield(Recipe recipe) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if ((Object)(object)recipe == (Object)null) { return false; } if ((int)GetItemType(recipe) == 5) { return true; } return (PrefabName(recipe) ?? "").IndexOf("Shield", StringComparison.OrdinalIgnoreCase) >= 0; } private static string[] DefaultOrder() { return new string[3] { "Shield", "Tower", "Other" }; } private static string FromPrefab(string prefab) { if (string.IsNullOrEmpty(prefab)) { return null; } for (int i = 0; i < ShieldTypeTokens.Length; i++) { string text = ShieldTypeTokens[i]; if (prefab.StartsWith(text, StringComparison.OrdinalIgnoreCase) && prefab.Length > text.Length) { return prefab.Substring(text.Length); } if (prefab.EndsWith(text, StringComparison.OrdinalIgnoreCase) && prefab.Length > text.Length + 2) { return prefab.Substring(0, prefab.Length - text.Length); } } return FromKnownStem(prefab); } private static string FromShared(string shared) { if (string.IsNullOrEmpty(shared)) { return null; } string text = SharedCleanup.Replace(shared, ""); for (int i = 0; i < 3; i++) { string input = SharedShieldTrim.Replace(text, ""); input = SharedShieldPrefix.Replace(input, ""); input = input.Trim('_', '-', ' '); if (input == text) { break; } text = input; } if (text.Length < 3) { return null; } return text; } private static string FromKnownStem(string blob) { if (string.IsNullOrEmpty(blob)) { return null; } for (int i = 0; i < MaterialStems.Length; i++) { if (blob.IndexOf(MaterialStems[i], StringComparison.OrdinalIgnoreCase) >= 0) { return MaterialStems[i]; } } return null; } private static string CanonicalizeMaterial(string raw) { if (string.IsNullOrEmpty(raw)) { return null; } string text = raw.Replace("-", "_"); if (text.IndexOf('_') >= 0) { string[] array = text.Split(new char[1] { '_' }); StringBuilder stringBuilder = new StringBuilder(); foreach (string text2 in array) { if (!string.IsNullOrEmpty(text2)) { stringBuilder.Append(char.ToUpperInvariant(text2[0])); if (text2.Length > 1) { stringBuilder.Append(text2.Substring(1)); } } } text = stringBuilder.ToString(); } if (text.Length > 0 && char.IsLower(text[0])) { text = char.ToUpperInvariant(text[0]) + text.Substring(1); } if (text.Equals("Blackmetal", StringComparison.OrdinalIgnoreCase)) { return "BlackMetal"; } if (text.Equals("Finewood", StringComparison.OrdinalIgnoreCase)) { return "FineWood"; } if (text.Equals("Serpentscale", StringComparison.OrdinalIgnoreCase) || text.Equals("Serpent", StringComparison.OrdinalIgnoreCase)) { return "Serpentscale"; } return text; } private static bool IsKnownMaterial(string mat) { for (int i = 0; i < MaterialStems.Length; i++) { if (mat.Equals(MaterialStems[i], StringComparison.OrdinalIgnoreCase)) { return true; } } return mat.Equals("Bronze", StringComparison.OrdinalIgnoreCase); } private static bool LooksVanillaShieldPrefab(string prefab) { if (string.IsNullOrEmpty(prefab)) { return false; } if (!prefab.StartsWith("Shield", StringComparison.OrdinalIgnoreCase)) { return prefab.StartsWith("TowerShield", StringComparison.OrdinalIgnoreCase); } return true; } private static string PrefabName(Recipe recipe) { if ((Object)(object)recipe?.m_item == (Object)null) { return null; } string name = ((Object)recipe.m_item).name; if (!string.IsNullOrEmpty(name)) { return name; } if (!((Object)(object)((Component)recipe.m_item).gameObject != (Object)null)) { return null; } return ((Object)((Component)recipe.m_item).gameObject).name; } private static string SharedName(Recipe recipe) { try { return recipe?.m_item?.m_itemData?.m_shared?.m_name; } catch { return null; } } private static ItemType GetItemType(Recipe recipe) { //IL_0036: 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_0045: Unknown result type (might be due to invalid IL or missing references) try { if (recipe?.m_item?.m_itemData?.m_shared != null) { return recipe.m_item.m_itemData.m_shared.m_itemType; } } catch { } return (ItemType)0; } private static int IndexOf(string[] order, string token) { for (int i = 0; i < order.Length; i++) { if (order[i].Equals(token, StringComparison.OrdinalIgnoreCase)) { return i; } } return order.Length + 5; } } internal static class StationFilter { public static void Apply(List<Recipe> recipes) { if (recipes == null || recipes.Count == 0) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); for (int num = recipes.Count - 1; num >= 0; num--) { if (!BelongsToStation(recipes[num], currentCraftingStation)) { recipes.RemoveAt(num); } } } public static bool BelongsToStation(Recipe recipe, CraftingStation current) { if ((Object)(object)recipe == (Object)null) { return false; } CraftingStation craftingStation = recipe.m_craftingStation; if ((Object)(object)current == (Object)null) { return (Object)(object)craftingStation == (Object)null; } if ((Object)(object)craftingStation != (Object)null) { if (string.IsNullOrEmpty(craftingStation.m_name) || string.IsNullOrEmpty(current.m_name)) { return false; } return craftingStation.m_name == current.m_name; } return current.m_showBasicRecipies; } } internal static class ToolSetDetector { private static readonly string[] MaterialStems = new string[21] { "BlackMetal", "Flametal", "Carapace", "Crystal", "Bronze", "Copper", "Silver", "Iron", "Flint", "Chitin", "Bone", "Abyssal", "Needle", "FineWood", "Wood", "HardAntler", "Antler", "Obsidian", "Ancient", "Ashlands", "Asksvin" }; private static readonly string[] ToolTypeTokens = new string[5] { "Cultivator", "Pickaxe", "Hammer", "Scythe", "Hoe" }; private static readonly Regex SharedCleanup = new Regex("^\\$?(item[_-]?)?", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedToolTrim = new Regex("[_-]?(cultivator|pickaxe|hammer|scythe|hoe)$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SharedToolPrefix = new Regex("^(cultivator|pickaxe|hammer|scythe|hoe)[_-]", RegexOptions.IgnoreCase | RegexOptions.Compiled); public static string SetKey(Recipe recipe, bool groupModded) { if ((Object)(object)recipe == (Object)null || !IsTool(recipe)) { return null; } string text = PrefabName(recipe) ?? ""; string text2 = SharedName(recipe) ?? ""; string blob = (text + " " + text2).Trim(); string text3 = FromPrefab(text); if (string.IsNullOrEmpty(text3)) { text3 = FromShared(text2); } if (string.IsNullOrEmpty(text3)) { text3 = FromKnownStem(blob); } if (string.IsNullOrEmpty(text3) && IsBareEarlyTool(text)) { text3 = "Wood"; } if (string.IsNullOrEmpty(text3) || text3.Length < 3) { return null; } text3 = CanonicalizeMaterial(text3); if (string.IsNullOrEmpty(text3)) { return null; } if (!groupModded && !IsKnownMaterial(text3) && !LooksVanillaToolPrefab(text)) { return null; } return "Tool" + text3; } public static int PieceOrder(Recipe recipe, string[] orderTokens) { string obj = PrefabName(recipe) ?? ""; string text = SharedName(recipe) ?? ""; string text2 = obj + " " + text; for (int i = 0; i < orderTokens.Length; i++) { string text3 = orderTokens[i]; if (!string.IsNullOrEmpty(text3) && !text3.Equals("Other", StringComparison.OrdinalIgnoreCase) && text2.IndexOf(text3, StringComparison.OrdinalIgnoreCase) >= 0) { return i; } } return orderTokens.Length + 10; } public static string[] ParseOrder(string csv) { if (string.IsNullOrEmpty(csv)) { return DefaultOrder(); } string[] array = csv.Split(new char[1] { ',' }); List<string> list = new List<string>(); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } if (list.Count == 0) { return DefaultOrder(); } return list.ToArray(); } public static bool IsTool(Recipe recipe) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 if ((Object)(object)recipe == (Object)null) { return false; } if (LooksToolPrefab(PrefabName(recipe) ?? "")) { return true; } re