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 OdinsReclaim v1.0.0
OdinsReclaim.dll
Decompiled 15 hours 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.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = "")] [assembly: AssemblyCompany("OdinsReclaim")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("OdinsReclaim")] [assembly: AssemblyTitle("OdinsReclaim")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OdinsReclaim { internal static class Banner { private const float Seconds = 4f; private const float FadeSeconds = 0.5f; private static GameObject s_root; private static CanvasGroup s_group; private static TMP_Text s_text; private static float s_until; internal static bool Show(string text) { InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)instance) || !InventoryGui.IsVisible()) { return false; } if (!Object.op_Implicit((Object)(object)s_root) && !Build(instance)) { return false; } s_text.text = text; s_root.SetActive(true); s_group.alpha = 1f; s_until = Time.unscaledTime + 4f; return true; } internal static void Tick() { if (Object.op_Implicit((Object)(object)s_root) && s_root.activeSelf) { float num = s_until - Time.unscaledTime; if (num <= 0f || !InventoryGui.IsVisible()) { s_root.SetActive(false); } else { s_group.alpha = Mathf.Clamp01(num / 0.5f); } } } private static bool Build(InventoryGui gui) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>(); Transform val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent.rootCanvas).transform : ((Component)gui).transform); TMP_Text recipeName = gui.m_recipeName; if (!Object.op_Implicit((Object)(object)recipeName)) { return false; } s_root = new GameObject("OdinsReclaim_Banner", new Type[1] { typeof(RectTransform) }); s_root.transform.SetParent(val, false); Canvas obj = s_root.AddComponent<Canvas>(); obj.overrideSorting = true; obj.sortingOrder = 30000; s_group = s_root.AddComponent<CanvasGroup>(); s_group.blocksRaycasts = false; s_group.interactable = false; RectTransform val2 = (RectTransform)s_root.transform; Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(0.5f, 1f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(0.5f, 1f); Place(); val2.sizeDelta = new Vector2(1100f, 46f); Image obj2 = s_root.AddComponent<Image>(); ((Graphic)obj2).color = new Color(0f, 0f, 0f, 0.8f); ((Graphic)obj2).raycastTarget = false; GameObject val4 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); val4.transform.SetParent(s_root.transform, false); RectTransform val5 = (RectTransform)val4.transform; val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val5.offsetMin = new Vector2(18f, 4f); val5.offsetMax = new Vector2(-18f, -4f); TextMeshProUGUI obj3 = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj3).font = recipeName.font; ((TMP_Text)obj3).fontSharedMaterial = recipeName.fontSharedMaterial; ((TMP_Text)obj3).enableAutoSizing = true; ((TMP_Text)obj3).fontSizeMin = 14f; ((TMP_Text)obj3).fontSizeMax = 24f; ((TMP_Text)obj3).alignment = (TextAlignmentOptions)514; ((Graphic)obj3).color = new Color(1f, 0.92f, 0.75f); ((TMP_Text)obj3).richText = true; ((Graphic)obj3).raycastTarget = false; s_text = (TMP_Text)(object)obj3; s_root.SetActive(false); return true; } internal static void Place() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)s_root)) { ((RectTransform)s_root.transform).anchoredPosition = new Vector2(0f, -24f) + Settings.BannerOffset.Value; } } } [HarmonyPatch] internal static class ChestButton { private const float ConfirmSeconds = 4f; private static Button s_button; private static float s_armedUntil = -1f; private static Container s_armedFor; private static bool s_hooked; [HarmonyPatch(typeof(InventoryGui), "Awake")] [HarmonyPostfix] private static void AfterAwake(InventoryGui __instance) { Disarm(); if (!GuiAccess.Ok || !Object.op_Implicit((Object)(object)__instance.m_stackAllButton)) { return; } try { s_button = GuiAccess.CloneButton(__instance.m_stackAllButton, "OdinsReclaim_ReclaimAll", "", OnClick); MakeIcon(s_button); UITooltip component = ((Component)s_button).GetComponent<UITooltip>(); if (Object.op_Implicit((Object)(object)component)) { component.m_text = "Reclaim all: break every item in this chest back into materials (drag to move)"; } ((Component)s_button).gameObject.AddComponent<DragMover>().Moved = delegate(Vector2 pos) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) Settings.ChestButtonPos.Value = pos; }; Place(__instance); if (!s_hooked) { s_hooked = true; Settings.ChestButtonPos.SettingChanged += delegate { Place(InventoryGui.instance); }; } } catch (Exception ex) { Plugin.Log.LogError((object)("Couldn't add the Reclaim all button: " + ex)); s_button = null; } } private static void MakeIcon(Button button) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) RectTransform val = (RectTransform)((Component)button).transform; Rect rect = val.rect; float num; if (!(((Rect)(ref rect)).height > 1f)) { num = val.sizeDelta.y; } else { rect = val.rect; num = ((Rect)(ref rect)).height; } float num2 = Mathf.Max(36f, num); val.sizeDelta = new Vector2(num2, num2); GameObject val2 = new GameObject("Icon", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(((Component)button).transform, false); RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = new Vector2(4f, 4f); val3.offsetMax = new Vector2(-4f, -4f); Image obj = val2.AddComponent<Image>(); obj.sprite = Ui.Icon("ui_recycle.png"); obj.preserveAspect = true; ((Graphic)obj).raycastTarget = false; } private static void Place(InventoryGui gui) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)gui) || !Object.op_Implicit((Object)(object)s_button)) { return; } RectTransform val = (RectTransform)((Component)s_button).transform; Vector2 value = Settings.ChestButtonPos.Value; if (value != Vector2.zero) { val.anchoredPosition = value; return; } RectTransform val2 = (RectTransform)((Component)gui.m_takeAllButton).transform; RectTransform val3 = (RectTransform)((Component)gui.m_stackAllButton).transform; Vector2 val4 = val3.anchoredPosition - val2.anchoredPosition; Vector2 anchoredPosition = val3.anchoredPosition; Vector2 normalized = ((Vector2)(ref val4)).normalized; Rect rect = val3.rect; float num = ((Rect)(ref rect)).width / 2f; rect = val.rect; val.anchoredPosition = anchoredPosition + normalized * (num + ((Rect)(ref rect)).width / 2f + 8f); if (((Vector2)(ref val4)).sqrMagnitude < 1f) { Vector2 anchoredPosition2 = val3.anchoredPosition; rect = val3.rect; val.anchoredPosition = anchoredPosition2 + new Vector2(((Rect)(ref rect)).width, 0f); } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] [HarmonyPostfix] private static void AfterUpdateContainer(InventoryGui __instance) { if (Object.op_Implicit((Object)(object)s_button)) { Container val = GuiAccess.CurrentContainer(__instance); bool flag = Settings.ChestEnabled.Value && Object.op_Implicit((Object)(object)val) && ((Component)__instance.m_stackAllButton).gameObject.activeInHierarchy; if (((Component)s_button).gameObject.activeSelf != flag) { ((Component)s_button).gameObject.SetActive(flag); } if (s_armedUntil >= 0f && (Time.time > s_armedUntil || (Object)(object)val != (Object)(object)s_armedFor)) { Disarm(); } } } private static void Disarm() { s_armedUntil = -1f; s_armedFor = null; } private static string ChestPrefab(Container chest) { if (!Object.op_Implicit((Object)(object)chest)) { return null; } return Utils.GetPrefabName(((Component)chest).gameObject); } private static void OnClick() { InventoryGui instance = InventoryGui.instance; Player p = Player.m_localPlayer; Container chest = (Object.op_Implicit((Object)(object)instance) ? GuiAccess.CurrentContainer(instance) : null); if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)chest) || !Settings.ChestEnabled.Value) { return; } try { if (s_armedUntil >= 0f && (Object)(object)s_armedFor == (Object)(object)chest && Time.time <= s_armedUntil) { Disarm(); ReclaimAll(p, chest); return; } int num = 0; Dictionary<string, int> reasons = new Dictionary<string, int>(); string chestPrefab = ChestPrefab(chest); foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { Plan plan = Yields.Make(allItem, p, Way.Chest, null, chestPrefab); if (plan.Ok) { num++; } else { Tally(reasons, plan.Problem); } } if (num == 0) { Plugin.Say(p, "Nothing in this chest can be reclaimed here" + Reasons(reasons), always: true); return; } float value = Settings.Rate.Value; string text = $"Break {num} item(s) in this chest back into materials? You get back about " + $"{Mathf.RoundToInt(value * 100f)}% of what they took to make. This can't be undone."; if (!Ui.Confirm("Reclaim all", text, delegate { ReclaimAll(p, chest); })) { s_armedUntil = Time.time + 4f; s_armedFor = chest; Plugin.Say(p, $"Click again to reclaim {num} item(s) from this chest", always: true); } } catch (Exception ex) { Plugin.Log.LogError((object)("Reclaim all failed: " + ex)); Disarm(); } } private static void ReclaimAll(Player p, Container chest) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)chest) || !Object.op_Implicit((Object)(object)instance) || (Object)(object)GuiAccess.CurrentContainer(instance) != (Object)(object)chest) { if (Object.op_Implicit((Object)(object)p)) { Plugin.Say(p, "The chest was closed, nothing was reclaimed", always: true); } return; } Inventory inventory = chest.GetInventory(); Vector3 dropAt = ((Component)chest).transform.position + Vector3.up; string chestPrefab = ChestPrefab(chest); int num = 0; int num2 = 0; int num3 = 0; Dictionary<string, int> reasons = new Dictionary<string, int>(); foreach (ItemData item in new List<ItemData>(inventory.GetAllItems())) { Plan plan = Yields.Make(item, p, Way.Chest, null, chestPrefab); if (!plan.Ok) { Tally(reasons, plan.Problem); continue; } if (!Moves.Fits(inventory, plan.Outputs, 1)) { num2++; continue; } ItemData val = Moves.Take(inventory, item, null); if (val != null) { num3 += Moves.Give(inventory, plan.Outputs, val.m_cheated, dropAt, p); num++; if (Settings.LogActions.Value) { Plugin.Log.LogInfo((object)$"Reclaim all: {Yields.PrefabName(val)} q{val.m_quality} x{val.m_stack} -> {plan.OutputText()}"); } } } if (num > 0) { CraftingStation craftingStation = CraftingStation.GetCraftingStation(((Component)p).transform.position); if (Object.op_Implicit((Object)(object)craftingStation)) { craftingStation.m_craftItemDoneEffects.Create(((Component)p).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } string text = $"Reclaimed {num} item(s)"; if (num2 > 0) { text += $", {num2} skipped (chest full)"; } if (num3 > 0) { text += $", {num3} material(s) fell next to the chest"; } Plugin.Say(p, text + Reasons(reasons), always: true); if (ReclaimTab.Active && GuiAccess.Ok) { GuiAccess.RefreshCrafting(instance); } } private static void Tally(Dictionary<string, int> reasons, string why) { if (!string.IsNullOrEmpty(why)) { reasons.TryGetValue(why, out var value); reasons[why] = value + 1; } } private static string Reasons(Dictionary<string, int> reasons) { if (reasons.Count == 0 || !Settings.ShowReasons.Value) { return ""; } string arg = ""; int num = 0; foreach (KeyValuePair<string, int> reason in reasons) { if (reason.Value > num) { num = reason.Value; arg = reason.Key; } } return $" ({num} item(s): {arg})"; } } internal static class EpicLootBridge { private static bool s_looked; private static MethodInfo s_magicJson; private static MethodInfo s_costsJson; private static readonly string[] Rarities = new string[6] { "Magic", "Rare", "Epic", "Legendary", "Mythic", "Ancient" }; private static ItemData s_lastItem; private static float s_lastTime = -10f; private static List<KeyValuePair<string, int>> s_last; internal static bool Present { get { if (!s_looked) { s_looked = true; Type type = AccessTools.TypeByName("EpicLoot.API"); if (type != null) { s_magicJson = AccessTools.Method(type, "GetMagicItemJson", new Type[1] { typeof(ItemData) }, (Type[])null); s_costsJson = AccessTools.Method(type, "GetEnchantCostsJson", new Type[2] { typeof(ItemData), typeof(int) }, (Type[])null); if (s_magicJson == null || s_costsJson == null) { Plugin.Log.LogWarning((object)"Epic Loot is installed but its API has changed: enchanting materials aren't given back"); } } } if (s_magicJson != null) { return s_costsJson != null; } return false; } } internal static List<KeyValuePair<string, int>> EnchantCosts(ItemData item) { if (item != null && item == s_lastItem && Time.unscaledTime - s_lastTime < 1f && s_last != null) { return s_last; } s_last = Read(item); s_lastItem = item; s_lastTime = Time.unscaledTime; return s_last; } private static List<KeyValuePair<string, int>> Read(ItemData item) { List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>(); if (item == null || !Present) { return list; } try { string text = s_magicJson.Invoke(null, new object[1] { item }) as string; if (string.IsNullOrEmpty(text)) { return list; } int num = -1; Match m = Regex.Match(text, "\"Rarity\"\\s*:\\s*(\\d+)"); if (m.Success) { num = int.Parse(m.Groups[1].Value); } else { m = Regex.Match(text, "\"Rarity\"\\s*:\\s*\"(\\w+)\""); if (m.Success) { num = Array.FindIndex(Rarities, (string r) => string.Equals(r, m.Groups[1].Value, StringComparison.OrdinalIgnoreCase)); } } if (num < 0) { return list; } string text2 = s_costsJson.Invoke(null, new object[2] { item, num }) as string; if (string.IsNullOrEmpty(text2)) { return list; } foreach (Match item2 in Regex.Matches(text2, "\\{[^{}]*\\}")) { Match match = Regex.Match(item2.Value, "\"Item\"\\s*:\\s*\"([^\"]*)\""); Match match2 = Regex.Match(item2.Value, "\"Amount\"\\s*:\\s*(-?\\d+)"); if (match.Success && match2.Success && int.TryParse(match2.Groups[1].Value, out var result) && result > 0) { list.Add(new KeyValuePair<string, int>(match.Groups[1].Value, result)); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Epic Loot enchant costs failed: " + (ex.InnerException?.Message ?? ex.Message))); list.Clear(); } return list; } } internal static class Groups { private static readonly HashSet<string> BossTrophies = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "TrophyEikthyr", "TrophyTheElder", "TrophyBonemass", "TrophyDragonQueen", "TrophyGoblinKing", "TrophySeekerQueen", "TrophyFader" }; private static Dictionary<string, List<string>> s_custom; private static HashSet<string> s_ores; private static HashSet<string> s_metals; private static HashSet<string> s_woods; private static HashSet<string> s_seeds; private static HashSet<string> s_crops; private static ObjectDB s_builtFor; internal static void ResetCustom() { s_custom = null; } internal static bool Matches(string entry, ItemData item, int depth = 0) { if (string.IsNullOrEmpty(entry) || item?.m_shared == null || depth > 4) { return false; } if (string.Equals(entry, Yields.PrefabName(item), StringComparison.OrdinalIgnoreCase)) { return true; } if (Custom().TryGetValue(entry, out var value)) { foreach (string item2 in value) { if (Matches(item2, item, depth + 1)) { return true; } } return false; } return BuiltIn(entry, item); } internal static bool AnyMatch(List<string> entries, ItemData item) { foreach (string entry in entries) { if (Matches(entry, item)) { return true; } } return false; } private static Dictionary<string, List<string>> Custom() { if (s_custom != null) { return s_custom; } s_custom = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase); string[] array = (Settings.CustomGroups.Value ?? "").Split(';'); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0) { string text2 = text.Substring(0, num).Trim(); List<string> list = Settings.SplitList(text.Substring(num + 1)); if (text2.Length > 0 && list.Count > 0) { s_custom[text2] = list; } } } return s_custom; } private static bool BuiltIn(string group, ItemData item) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Invalid comparison between Unknown and I4 //IL_06c1: Unknown result type (might be due to invalid IL or missing references) //IL_06c4: Invalid comparison between Unknown and I4 //IL_06da: Unknown result type (might be due to invalid IL or missing references) //IL_06dd: Invalid comparison between Unknown and I4 //IL_06e0: Unknown result type (might be due to invalid IL or missing references) //IL_06e3: Invalid comparison between Unknown and I4 //IL_066a: Unknown result type (might be due to invalid IL or missing references) //IL_066c: Invalid comparison between Unknown and I4 //IL_0685: Unknown result type (might be due to invalid IL or missing references) //IL_0688: Invalid comparison between Unknown and I4 //IL_05cf: Unknown result type (might be due to invalid IL or missing references) //IL_05d2: Invalid comparison between Unknown and I4 //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_0671: Invalid comparison between Unknown and I4 //IL_06aa: Unknown result type (might be due to invalid IL or missing references) //IL_06ad: Invalid comparison between Unknown and I4 //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_0667: Invalid comparison between Unknown and I4 //IL_0680: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Invalid comparison between Unknown and I4 //IL_0612: Unknown result type (might be due to invalid IL or missing references) //IL_0619: Invalid comparison between Unknown and I4 //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_06d7: Invalid comparison between Unknown and I4 //IL_068a: Unknown result type (might be due to invalid IL or missing references) //IL_068d: Invalid comparison between Unknown and I4 //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Invalid comparison between Unknown and I4 //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_05fd: Invalid comparison between Unknown and I4 //IL_069e: Unknown result type (might be due to invalid IL or missing references) //IL_06a1: Invalid comparison between Unknown and I4 //IL_05d9: Unknown result type (might be due to invalid IL or missing references) //IL_05df: Invalid comparison between Unknown and I4 //IL_0606: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Invalid comparison between Unknown and I4 //IL_0692: Unknown result type (might be due to invalid IL or missing references) //IL_0695: Invalid comparison between Unknown and I4 //IL_062c: Unknown result type (might be due to invalid IL or missing references) //IL_0632: Invalid comparison between Unknown and I4 //IL_0698: Unknown result type (might be due to invalid IL or missing references) //IL_069b: Invalid comparison between Unknown and I4 //IL_0659: Unknown result type (might be due to invalid IL or missing references) //IL_0660: Invalid comparison between Unknown and I4 //IL_06a4: Unknown result type (might be due to invalid IL or missing references) //IL_06a7: Invalid comparison between Unknown and I4 //IL_0678: Unknown result type (might be due to invalid IL or missing references) //IL_067b: Invalid comparison between Unknown and I4 //IL_063b: Unknown result type (might be due to invalid IL or missing references) //IL_0641: Invalid comparison between Unknown and I4 //IL_061e: Unknown result type (might be due to invalid IL or missing references) //IL_0621: Invalid comparison between Unknown and I4 //IL_05e8: Unknown result type (might be due to invalid IL or missing references) //IL_05ee: Invalid comparison between Unknown and I4 //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Invalid comparison between Unknown and I4 SharedData shared = item.m_shared; ItemType itemType = shared.m_itemType; bool flag = (int)itemType == 3 || (int)itemType == 14 || (int)itemType == 22 || (int)itemType == 4; bool flag2 = (int)itemType == 2; bool flag3 = shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f; string item2 = Yields.PrefabName(item) ?? ""; switch (group.Replace(" ", "").ToLowerInvariant()) { case "all": return true; case "food": return flag2 && flag3; case "potion": case "potions": if (flag2) { return !flag3; } return false; case "fish": return (int)itemType == 21; case "swords": if (flag) { return (int)shared.m_skillType == 1; } return false; case "axes": if (flag) { return (int)shared.m_skillType == 7; } return false; case "clubs": if (flag) { return (int)shared.m_skillType == 3; } return false; case "knives": if (flag) { return (int)shared.m_skillType == 2; } return false; case "pickaxes": if ((int)shared.m_skillType == 12) { if (!flag) { return (int)itemType == 19; } return true; } return false; case "polearms": if (flag) { return (int)shared.m_skillType == 4; } return false; case "spears": if (flag) { return (int)shared.m_skillType == 5; } return false; case "bows": if (flag) { return (int)shared.m_skillType == 8; } return false; case "crossbows": if (flag) { return (int)shared.m_skillType == 14; } return false; case "shields": return (int)itemType == 5; case "armour": case "armor": if ((int)itemType != 7 && (int)itemType != 11 && (int)itemType != 17) { return (int)itemType == 12; } return true; case "helmets": return (int)itemType == 6; case "ammo": case "ammunition": if ((int)itemType != 9) { return (int)itemType == 23; } return true; case "utility": case "utilities": return (int)itemType == 18; case "trinkets": return (int)itemType == 24; case "tools": return (int)itemType == 19; case "equipment": return (int)itemType == 15; case "trophy": case "trophies": if ((int)itemType == 13) { return !BossTrophies.Contains(item2); } return false; case "bosstrophy": case "bosstrophies": if ((int)itemType == 13) { return BossTrophies.Contains(item2); } return false; case "materials": return (int)itemType == 1; case "misc": case "miscellaneous": return (int)itemType == 16; case "customizations": return (int)itemType == 10; case "ores": Build(); return s_ores.Contains(item2); case "metals": Build(); return s_metals.Contains(item2); case "woods": Build(); return s_woods.Contains(item2); case "seeds": Build(); return s_seeds.Contains(item2); case "crops": Build(); return s_crops.Contains(item2); default: return false; } } private static void Build() { if (s_ores != null && (Object)(object)s_builtFor == (Object)(object)ObjectDB.instance) { return; } s_builtFor = ObjectDB.instance; s_ores = new HashSet<string>(StringComparer.OrdinalIgnoreCase); s_metals = new HashSet<string>(StringComparer.OrdinalIgnoreCase); s_woods = new HashSet<string>(StringComparer.OrdinalIgnoreCase); s_seeds = new HashSet<string>(StringComparer.OrdinalIgnoreCase); s_crops = new HashSet<string>(StringComparer.OrdinalIgnoreCase); try { ZNetScene instance = ZNetScene.instance; string[] array = new string[3] { "smelter", "blastfurnace", "charcoal_kiln" }; foreach (string text in array) { object obj; if (!Object.op_Implicit((Object)(object)instance)) { obj = null; } else { GameObject prefab = instance.GetPrefab(text); obj = ((prefab != null) ? prefab.GetComponent<Smelter>() : null); } Smelter val = (Smelter)obj; if (!Object.op_Implicit((Object)(object)val)) { continue; } foreach (ItemConversion item in val.m_conversion) { if (!((Object)(object)item?.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null)) { if (text == "charcoal_kiln") { s_woods.Add(((Object)((Component)item.m_from).gameObject).name); continue; } s_ores.Add(((Object)((Component)item.m_from).gameObject).name); s_metals.Add(((Object)((Component)item.m_to).gameObject).name); } } } object obj2; if (!Object.op_Implicit((Object)(object)ObjectDB.instance)) { obj2 = null; } else { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Cultivator"); obj2 = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null); } ItemDrop val2 = (ItemDrop)obj2; PieceTable val3 = (Object.op_Implicit((Object)(object)val2) ? val2.m_itemData.m_shared.m_buildPieces : null); if (!((Object)(object)val3 != (Object)null)) { return; } foreach (GameObject piece in val3.m_pieces) { Plant val4 = (Object.op_Implicit((Object)(object)piece) ? piece.GetComponent<Plant>() : null); Piece val5 = (Object.op_Implicit((Object)(object)piece) ? piece.GetComponent<Piece>() : null); if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val5)) { continue; } Requirement[] resources = val5.m_resources; foreach (Requirement val6 in resources) { if (Object.op_Implicit((Object)(object)val6?.m_resItem)) { s_seeds.Add(((Object)((Component)val6.m_resItem).gameObject).name); } } GameObject[] grownPrefabs = val4.m_grownPrefabs; foreach (GameObject val7 in grownPrefabs) { Pickable val8 = (Object.op_Implicit((Object)(object)val7) ? val7.GetComponent<Pickable>() : null); if (Object.op_Implicit((Object)(object)val8) && Object.op_Implicit((Object)(object)val8.m_itemPrefab)) { s_crops.Add(((Object)val8.m_itemPrefab).name); } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't build the Ores/Metals/Woods/Seeds/Crops groups: " + ex.Message)); } } } internal static class GuiAccess { private static FieldRef<InventoryGui, Container> s_container; private static FieldRef<InventoryGui, float> s_craftTimer; private static FieldRef<InventoryGui, float> s_listBaseSize; private static FieldInfo s_available; private static FieldInfo s_selected; private static MethodInfo s_pairRecipe; private static MethodInfo s_pairItem; private static MethodInfo s_pairElement; private static MethodInfo s_addRecipeToList; private static MethodInfo s_updateCraftingPanel; private static MethodInfo s_setRecipe; private static FieldRef<InventoryGrid, List<InventoryElement>> s_elements; private static FieldRef<InventoryGui, ItemData> s_dragItem; private static FieldRef<InventoryGui, Inventory> s_dragInventory; private static FieldRef<InventoryGui, int> s_dragAmount; private static MethodInfo s_setupDrag; internal static bool Ok { get; private set; } internal static bool DragOk { get; private set; } internal static void Init() { try { s_container = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); s_craftTimer = AccessTools.FieldRefAccess<InventoryGui, float>("m_craftTimer"); s_listBaseSize = AccessTools.FieldRefAccess<InventoryGui, float>("m_recipeListBaseSize"); s_available = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes"); s_selected = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe"); Type type = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair"); s_pairRecipe = AccessTools.PropertyGetter(type, "Recipe"); s_pairItem = AccessTools.PropertyGetter(type, "ItemData"); s_pairElement = AccessTools.PropertyGetter(type, "InterfaceElement"); s_addRecipeToList = AccessTools.Method(typeof(InventoryGui), "AddRecipeToList", new Type[4] { typeof(Player), typeof(Recipe), typeof(ItemData), typeof(bool) }, (Type[])null); s_updateCraftingPanel = AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) }, (Type[])null); s_setRecipe = AccessTools.Method(typeof(InventoryGui), "SetRecipe", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); s_elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements"); s_dragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem"); s_dragInventory = AccessTools.FieldRefAccess<InventoryGui, Inventory>("m_dragInventory"); s_dragAmount = AccessTools.FieldRefAccess<InventoryGui, int>("m_dragAmount"); s_setupDrag = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3] { typeof(ItemData), typeof(Inventory), typeof(int) }, (Type[])null); DragOk = s_setupDrag != null; Ok = s_available != null && s_selected != null && s_pairRecipe != null && s_pairItem != null && s_pairElement != null && s_addRecipeToList != null && s_updateCraftingPanel != null && s_setRecipe != null; } catch (Exception ex) { Plugin.Log.LogError((object)("Couldn't find parts of the game's inventory screen (game update?): " + ex.Message)); Ok = false; } if (!Ok) { Plugin.Log.LogError((object)"The Reclaim tab is off: the game's crafting list code has changed."); } } internal static Container CurrentContainer(InventoryGui gui) { if (s_container == null) { return null; } return s_container.Invoke(gui); } internal static float CraftTimer(InventoryGui gui) { if (s_craftTimer == null) { return -1f; } return s_craftTimer.Invoke(gui); } internal static bool Dragging(InventoryGui gui, out ItemData item, out Inventory inv, out int amount) { item = (DragOk ? s_dragItem.Invoke(gui) : null); inv = (DragOk ? s_dragInventory.Invoke(gui) : null); amount = (DragOk ? s_dragAmount.Invoke(gui) : 0); if (item != null) { return inv != null; } return false; } internal static void StopDragging(InventoryGui gui) { if (DragOk) { s_setupDrag.Invoke(gui, new object[3] { null, null, 1 }); } } internal static List<InventoryElement> Elements(InventoryGrid grid) { if (s_elements == null) { return null; } return s_elements.Invoke(grid); } internal static void Selected(InventoryGui gui, out Recipe recipe, out ItemData item) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown object value = s_selected.GetValue(gui); recipe = (Recipe)s_pairRecipe.Invoke(value, null); item = (ItemData)s_pairItem.Invoke(value, null); } internal static void ClearList(InventoryGui gui) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown IList list = (IList)s_available.GetValue(gui); foreach (object item in list) { GameObject val = (GameObject)s_pairElement.Invoke(item, null); if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } list.Clear(); } internal static GameObject LastElement(InventoryGui gui) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown IList list = (IList)s_available.GetValue(gui); if (list.Count <= 0) { return null; } return (GameObject)s_pairElement.Invoke(list[list.Count - 1], null); } internal static void ClearSelection(InventoryGui gui) { s_setRecipe.Invoke(gui, new object[2] { -1, false }); } internal static int ListCount(InventoryGui gui) { return ((IList)s_available.GetValue(gui)).Count; } internal static void AddToList(InventoryGui gui, Player p, Recipe recipe, ItemData item, bool canCraft) { s_addRecipeToList.Invoke(gui, new object[4] { p, recipe, item, canCraft }); } internal static void SizeList(InventoryGui gui) { float num = Mathf.Max(s_listBaseSize.Invoke(gui), (float)ListCount(gui) * gui.m_recipeListSpace); gui.m_recipeListRoot.SetSizeWithCurrentAnchors((Axis)1, num); } internal static void RefreshCrafting(InventoryGui gui) { s_updateCraftingPanel.Invoke(gui, new object[1] { false }); } internal static Button CloneButton(Button original, string name, string label, Action onClick) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown GameObject val = Object.Instantiate<GameObject>(((Component)original).gameObject, ((Component)original).transform.parent); ((Object)val).name = name; UIGamePad[] componentsInChildren = val.GetComponentsInChildren<UIGamePad>(true); foreach (UIGamePad val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2.m_hint)) { Object.Destroy((Object)(object)val2.m_hint); } Object.Destroy((Object)(object)val2); } Button component = val.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener((UnityAction)delegate { onClick(); }); SetLabel(component, label); return component; } internal static void SetLabel(Button button, string label) { TMP_Text[] componentsInChildren = ((Component)button).GetComponentsInChildren<TMP_Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = label; } } } [HarmonyPatch] internal static class InventoryKeys { private static readonly HashSet<ItemData> s_marked = new HashSet<ItemData>(); private static bool s_painting; private static bool s_paintMark; private static readonly HashSet<Vector2i> s_markedPos = new HashSet<Vector2i>(); private static float s_nextDelete; private const float DeleteCooldown = 0.3f; private static readonly Dictionary<InventoryElement, Image> s_outlines = new Dictionary<InventoryElement, Image>(); private static int s_outlinesShown; private static Sprite s_border; internal static void Tick() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !InventoryGui.IsVisible() || Typing() || Covered(InventoryGui.instance)) { ClearMarks(); return; } if (Settings.Down(Settings.UndoShortcut.Value)) { Undo.Run(localPlayer); Refresh(); return; } Trash(localPlayer); if (Settings.KeyEnabled.Value && Settings.Down(Settings.KeyShortcut.Value)) { DeleteKey(localPlayer); } } private static bool Covered(InventoryGui gui) { if (Object.op_Implicit((Object)(object)gui) && !gui.IsSkillsPanelOpen && !gui.IsTextPanelOpen && !gui.IsTrophisPanelOpen && !gui.IsAchievementsPanelOpen && (!Object.op_Implicit((Object)(object)gui.m_splitDialog) || !gui.m_splitDialog.IsActive)) { if (Object.op_Implicit((Object)(object)gui.m_variantDialog)) { return ((Component)gui.m_variantDialog).gameObject.activeSelf; } return false; } return true; } private static bool Typing() { if (!Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !TextInput.IsVisible()) { return Menu.IsVisible(); } return true; } private static void DeleteKey(Player p) { //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < s_nextDelete) { return; } s_nextDelete = Time.unscaledTime + 0.3f; if (Settings.KeyAdminsOnly.Value && !SynchronizationManager.Instance.PlayerIsAdmin) { Plugin.Say(p, "Only admins can use the delete key on this server"); return; } Inventory inventory = ((Humanoid)p).GetInventory(); ItemData val = Hovered(inventory); if (val == null) { return; } string text = Localization.instance.Localize(val.m_shared.m_name); if (val.m_shared.m_questItem) { Plugin.Say(p, text + " can't be deleted"); return; } if (Settings.ProtectEnchanted.Value && Yields.IsEnchanted(val)) { Plugin.Say(p, text + " is enchanted and protected (Epic Loot's Sacrifice gives its materials back)"); return; } Plan plan = Yields.Make(val, p, Way.Key); if (plan.Ok && !Moves.Fits(inventory, plan.Outputs, 1)) { Plugin.Say(p, "Not enough room in your inventory for the materials"); return; } ItemData val2 = Moves.Take(inventory, val, (Humanoid)(object)p); if (val2 == null) { return; } Undo.Entry e = Undo.Record(p, inventory, new List<ItemData> { val2 }, plan.Ok ? plan.Outputs : null, "deleted " + text); int num = 0; if (plan.Ok) { try { num = Moves.Give(inventory, plan.Outputs, val2.m_cheated, Moves.Feet(p), p); } catch (Exception arg) { Undo.Forget(e); Moves.PutBack(inventory, val2, Moves.Feet(p)); Plugin.Log.LogError((object)$"Deleting {text} failed half-way, the item was put back: {arg}"); Plugin.Say(p, "Something went wrong; " + text + " was put back", always: true); Refresh(); return; } } if (num > 0) { Undo.Forget(e); } string text2 = (plan.Ok ? ("Deleted " + text + ", got back " + plan.OutputText()) : ("Deleted " + text + " (nothing back: " + plan.Problem + ")")); Plugin.Say(p, text2 + ((num > 0) ? " (some fell at your feet)" : Plugin.UndoHint()), always: true); if (Settings.LogActions.Value) { Plugin.Log.LogInfo((object)($"Delete key: {Yields.PrefabName(val2)} q{val2.m_quality} x{val2.m_stack} -> " + (plan.Ok ? plan.OutputText() : ("nothing (" + plan.Problem + ")")))); } Refresh(); } private static bool Holding() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (Settings.TrashEnabled.Value && (int)Settings.TrashHoldKey.Value != 0) { return ZInput.GetKey(Settings.TrashHoldKey.Value, false); } return false; } private static void Trash(Player p) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!Holding()) { ClearMarks(); return; } Inventory inv = ((Humanoid)p).GetInventory(); s_marked.RemoveWhere((ItemData i) => !inv.ContainsItem(i)); if (ZInput.GetMouseButtonDown(1)) { ItemData val = Hovered(inv); if (val != null) { s_paintMark = !s_marked.Contains(val); s_painting = true; Mark(p, val, s_paintMark); } } else if (s_painting && ZInput.GetMouseButton(1)) { ItemData val2 = Hovered(inv); if (val2 != null) { Mark(p, val2, s_paintMark); } } if (!ZInput.GetMouseButton(1)) { s_painting = false; } if ((int)Settings.TrashDeleteKey.Value != 0 && ZInput.GetKeyDown(Settings.TrashDeleteKey.Value, false)) { DeleteMarked(p, inv); } } private static void Mark(Player p, ItemData item, bool on) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (on ? s_marked.Add(item) : s_marked.Remove(item)) { Plugin.Say(p, $"Marked {s_marked.Count} item(s) to delete. {KeyName(Settings.TrashDeleteKey.Value)} " + "deletes them, let go of " + KeyName(Settings.TrashHoldKey.Value) + " to cancel", always: true); } } private static void DeleteMarked(Player p, Inventory inv) { if (s_marked.Count == 0) { return; } List<ItemData> list = new List<ItemData>(); foreach (ItemData item in new List<ItemData>(s_marked)) { if (!item.m_shared.m_questItem) { ItemData val = Moves.Take(inv, item, (Humanoid)(object)p); if (val != null) { list.Add(val); } } } s_marked.Clear(); s_painting = false; if (list.Count == 0) { return; } Undo.Record(p, inv, list, null, $"deleted {list.Count} marked item(s)"); Plugin.Say(p, $"Deleted {list.Count} marked item(s)" + Plugin.UndoHint(), always: true); if (Settings.LogActions.Value) { foreach (ItemData item2 in list) { Plugin.Log.LogInfo((object)$"Trash: {Yields.PrefabName(item2)} q{item2.m_quality} x{item2.m_stack}"); } } Refresh(); } private static string KeyName(KeyCode k) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Settings.KeyText(k); } private static void ClearMarks() { s_marked.Clear(); s_painting = false; } [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")] [HarmonyPrefix] private static bool BeforeRightClick() { return !Holding(); } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] [HarmonyPostfix] private static void AfterGridUpdate(InventoryGrid __instance) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || __instance.GetInventory() != ((Humanoid)localPlayer).GetInventory() || (s_marked.Count == 0 && s_outlinesShown == 0)) { return; } List<InventoryElement> list = GuiAccess.Elements(__instance); if (list == null) { return; } s_markedPos.Clear(); foreach (ItemData item in s_marked) { s_markedPos.Add(item.m_gridPos); } Color value = Settings.TrashColor.Value; int num = 0; foreach (InventoryElement item2 in list) { if (!Object.op_Implicit((Object)(object)item2)) { continue; } bool flag = s_markedPos.Contains(item2.Position); s_outlines.TryGetValue(item2, out var value2); if (flag && !Object.op_Implicit((Object)(object)value2)) { Image val = (s_outlines[item2] = MakeOutline(item2)); value2 = val; } if (Object.op_Implicit((Object)(object)value2)) { if (((Component)value2).gameObject.activeSelf != flag) { ((Component)value2).gameObject.SetActive(flag); } if (flag) { ((Graphic)value2).color = value; num++; } } } s_outlinesShown = num; if (num == 0) { s_outlines.Clear(); } } private static Image MakeOutline(InventoryElement e) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("OdinsReclaim_Mark", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((Component)e).transform, false); val.transform.SetAsLastSibling(); RectTransform val2 = (RectTransform)val.transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; Vector2 offsetMin = (val2.offsetMax = Vector2.zero); val2.offsetMin = offsetMin; Image obj = val.AddComponent<Image>(); obj.sprite = Border(); obj.type = (Type)1; ((Graphic)obj).raycastTarget = false; return obj; } private static Sprite Border() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)s_border)) { return s_border; } Texture2D val = new Texture2D(32, 32, (TextureFormat)4, false) { name = "OdinsReclaim_Border", filterMode = (FilterMode)0, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { array[i * 32 + j] = ((j < 3 || i < 3 || j >= 29 || i >= 29) ? new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue) : new Color32((byte)0, (byte)0, (byte)0, (byte)0)); } } val.SetPixels32(array); val.Apply(false, true); ((Object)val).hideFlags = (HideFlags)(((Object)val).hideFlags | 0x20); s_border = Sprite.Create(val, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(4f, 4f, 4f, 4f)); ((Object)s_border).name = "OdinsReclaim_Border"; Sprite obj = s_border; ((Object)obj).hideFlags = (HideFlags)(((Object)obj).hideFlags | 0x20); return s_border; } internal static bool IsMarked(ItemData item) { if (item != null) { return s_marked.Contains(item); } return false; } private static ItemData Hovered(Inventory inv) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) InventoryGui instance = InventoryGui.instance; if (!Object.op_Implicit((Object)(object)instance)) { return null; } Vector2 val = Vector2.op_Implicit(ZInput.pointerPosition); InventoryGrid[] componentsInChildren = ((Component)instance).GetComponentsInChildren<InventoryGrid>(); foreach (InventoryGrid val2 in componentsInChildren) { if (val2.GetInventory() != inv) { continue; } List<InventoryElement> list = GuiAccess.Elements(val2); if (list == null) { continue; } foreach (InventoryElement item in list) { if (!Object.op_Implicit((Object)(object)item)) { continue; } RectTransform elementRectTransform = item.GetElementRectTransform(); if (Object.op_Implicit((Object)(object)elementRectTransform)) { Rect rect = elementRectTransform.rect; if (((Rect)(ref rect)).Contains(((Transform)elementRectTransform).InverseTransformPoint(Vector2.op_Implicit(val)))) { return inv.GetItemAt(item.Position.x, item.Position.y); } } } } return null; } private static void Refresh() { InventoryGui instance = InventoryGui.instance; if (Object.op_Implicit((Object)(object)instance) && InventoryGui.IsVisible() && GuiAccess.Ok) { GuiAccess.RefreshCrafting(instance); } } } [HarmonyPatch] internal static class KeyHints { private static RectTransform s_box; private static TMP_Text s_text; private static float s_nextText; private const string Key = "<color=#ffd84a>"; private const string End = "</color>"; [HarmonyPatch(typeof(InventoryGui), "Awake")] [HarmonyPostfix] private static void AfterAwake(InventoryGui __instance) { s_box = null; if (!Object.op_Implicit((Object)(object)__instance.m_player) || !Object.op_Implicit((Object)(object)__instance.m_armor)) { return; } try { Build(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Couldn't add the key hints: " + ex)); if (Object.op_Implicit((Object)(object)s_box)) { Object.Destroy((Object)(object)((Component)s_box).gameObject); } s_box = null; } } private static void Build(InventoryGui gui) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) Transform val = (Object.op_Implicit((Object)(object)gui.m_weight) ? TrashCan.TabOf(gui.m_armor.transform, gui.m_weight.transform) : null); GameObject val2 = new GameObject("OdinsReclaim_KeyHints", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent((Transform)(Object.op_Implicit((Object)(object)val) ? ((object)val.parent) : ((object)gui.m_player)), false); val2.transform.SetAsLastSibling(); s_box = (RectTransform)val2.transform; s_box.pivot = new Vector2(0f, 1f); s_box.sizeDelta = new Vector2(380f, 100f); Image obj = val2.AddComponent<Image>(); ((Graphic)obj).color = new Color(0.08f, 0.06f, 0.04f, 0.78f); ((Graphic)obj).raycastTarget = false; GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); val3.transform.SetParent(val2.transform, false); RectTransform val4 = (RectTransform)val3.transform; val4.anchorMin = Vector2.zero; val4.anchorMax = Vector2.one; val4.offsetMin = new Vector2(12f, 6f); val4.offsetMax = new Vector2(-12f, -6f); TextMeshProUGUI obj2 = val3.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj2).font = gui.m_armor.font; ((TMP_Text)obj2).fontSharedMaterial = gui.m_armor.fontSharedMaterial; ((TMP_Text)obj2).enableAutoSizing = true; ((TMP_Text)obj2).fontSizeMin = 11f; ((TMP_Text)obj2).fontSizeMax = 17f; ((TMP_Text)obj2).alignment = (TextAlignmentOptions)4097; ((Graphic)obj2).color = new Color(0.93f, 0.88f, 0.76f); ((TMP_Text)obj2).richText = true; ((Graphic)obj2).raycastTarget = false; s_text = (TMP_Text)(object)obj2; val2.SetActive(false); } [HarmonyPatch(typeof(InventoryGui), "UpdateInventory")] [HarmonyPostfix] private static void AfterUpdateInventory(InventoryGui __instance) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_box)) { return; } List<string> list = (Settings.ShowKeyHints.Value ? Lines() : null); bool flag = list != null && list.Count > 0; if (((Component)s_box).gameObject.activeSelf != flag) { ((Component)s_box).gameObject.SetActive(flag); s_nextText = 0f; } if (flag) { Vector3[] array = (Vector3[])(object)new Vector3[4]; __instance.m_player.GetWorldCorners(array); ((Transform)s_box).position = array[3]; RectTransform obj = s_box; obj.anchoredPosition += new Vector2(8f, -8f) + Settings.KeyHintsOffset.Value; if (!(Time.unscaledTime < s_nextText)) { s_nextText = Time.unscaledTime + 1f; s_text.text = string.Join("\n", list); s_box.sizeDelta = new Vector2(380f, 14f + 22f * (float)list.Count); } } } [HarmonyPatch(typeof(InventoryGui), "Hide")] [HarmonyPostfix] private static void AfterHide() { if (Object.op_Implicit((Object)(object)s_box)) { ((Component)s_box).gameObject.SetActive(false); } } private static List<string> Lines() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); if (Settings.TrashEnabled.Value && (int)Settings.TrashHoldKey.Value != 0) { string text = Settings.KeyText(Settings.TrashHoldKey.Value); list.Add("Hold <color=#ffd84a>" + text + "</color> + <color=#ffd84a>right-click</color>: mark items to delete"); if ((int)Settings.TrashDeleteKey.Value != 0) { list.Add("Hold <color=#ffd84a>" + text + "</color> + <color=#ffd84a>" + Settings.KeyText(Settings.TrashDeleteKey.Value).ToLowerInvariant() + "</color>: delete the marked items"); } } if (Settings.TrashCanEnabled.Value) { list.Add("Pick an item up, click the <color=#ffd84a>trash can</color>: delete it"); } if (Settings.KeyEnabled.Value && (!Settings.KeyAdminsOnly.Value || SynchronizationManager.Instance.PlayerIsAdmin)) { list.Add("<color=#ffd84a>" + Settings.ShortcutText(Settings.KeyShortcut.Value) + "</color>: delete the item under the mouse, get its materials"); } if (Settings.UndoSeconds.Value > 0) { KeyboardShortcut value = Settings.UndoShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { list.Add("<color=#ffd84a>" + Settings.ShortcutText(Settings.UndoShortcut.Value) + "</color>: undo"); } } return list; } } internal static class Moves { internal static bool Fits(Inventory inv, List<Output> outputs, int freedSlots) { int num = inv.GetEmptySlots() + freedSlots; foreach (Output output in outputs) { SharedData shared = output.Item.m_itemData.m_shared; int num2 = Mathf.Max(1, shared.m_maxStackSize); int num3 = output.Amount; if (num2 > 1) { num3 -= inv.FindFreeStackSpace(shared.m_name, (float)Game.m_worldLevel); } if (num3 > 0) { num -= (num3 + num2 - 1) / num2; } } return num >= 0; } internal static ItemData Take(Inventory inv, ItemData item, Humanoid owner) { if (inv == null || item == null || !inv.ContainsItem(item)) { return null; } if (Object.op_Implicit((Object)(object)owner)) { owner.RemoveEquipAction(item); if (item.m_equipped) { owner.UnequipItem(item, false); } } ItemData val = item.Clone(); val.m_equipped = false; if (!inv.RemoveItem(item)) { return null; } return val; } internal static ItemData TakeAmount(Inventory inv, ItemData item, int amount, Humanoid owner) { if (inv == null || item == null || !inv.ContainsItem(item) || amount <= 0) { return null; } if (amount >= item.m_stack) { return Take(inv, item, owner); } ItemData val = item.Clone(); val.m_stack = amount; val.m_equipped = false; if (!inv.RemoveItem(item, amount)) { return null; } return val; } internal static int Give(Inventory inv, List<Output> outputs, bool cheated, Vector3 dropAt, Player crafter = null) { //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) long crafterId = 0L; string crafterName = ""; if (Object.op_Implicit((Object)(object)crafter) && Settings.ApplyCrafter.Value) { crafterId = crafter.GetPlayerID(); crafterName = crafter.GetPlayerName(); } int num = 0; foreach (Output output in outputs) { ItemData itemData = output.Item.m_itemData; int num2 = Mathf.Max(1, itemData.m_shared.m_maxStackSize); int num3 = output.Amount; while (num3 > 0) { int num4 = Mathf.Min(num3, num2); num3 -= num4; ItemData val = NewStack(output.Item, num4, cheated, crafterId, crafterName); if (!inv.AddItem(val) && val.m_stack > 0) { num += val.m_stack; ItemDrop.DropItem(val, val.m_stack, dropAt, Quaternion.identity); } } } return num; } private static ItemData NewStack(ItemDrop prefab, int amount, bool cheated, long crafterId, string crafterName) { ItemData val = prefab.m_itemData.Clone(); val.m_dropPrefab = ((Component)prefab).gameObject; val.m_stack = amount; val.m_quality = Mathf.Max(1, val.m_quality); val.m_durability = val.GetMaxDurability(); val.m_worldLevel = (byte)Game.m_worldLevel; val.m_equipped = false; val.m_cheated = cheated && !PlayerProfile.s_bypassCheatChecks; val.m_crafterID = crafterId; val.m_crafterName = crafterName ?? ""; return val; } internal static bool TakeBack(Inventory inv, string sharedName, int amount) { List<ItemData> list = new List<ItemData>(); int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (!(allItem.m_shared.m_name != sharedName) && !allItem.m_equipped) { list.Add(allItem); num += allItem.m_stack; } } if (num < amount) { return false; } list.Sort((ItemData a, ItemData b) => a.m_stack.CompareTo(b.m_stack)); foreach (ItemData item in list) { if (amount <= 0) { break; } int num2 = Mathf.Min(item.m_stack, amount); if (inv.RemoveItem(item, num2)) { amount -= num2; } } return amount <= 0; } internal static int Count(Inventory inv, string sharedName) { int num = 0; foreach (ItemData allItem in inv.GetAllItems()) { if (allItem.m_shared.m_name == sharedName && !allItem.m_equipped) { num += allItem.m_stack; } } return num; } internal static void PutBack(Inventory inv, ItemData item, Vector3 dropAt) { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) Vector2i gridPos = item.m_gridPos; if ((gridPos.x < 0 || gridPos.y < 0 || gridPos.x >= inv.GetWidth() || gridPos.y >= inv.GetHeight() || inv.GetItemAt(gridPos.x, gridPos.y) != null || !inv.AddItem(item, gridPos)) && !inv.AddItem(item) && item.m_stack > 0 && Object.op_Implicit((Object)(object)item.m_dropPrefab)) { ItemDrop.DropItem(item, item.m_stack, dropAt, Quaternion.identity); Plugin.Log.LogWarning((object)("Undo: no room for " + item.m_shared.m_name + ", dropped it at your feet")); } } internal static Vector3 Feet(Player p) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return ((Component)p).transform.position + Vector3.up; } } [BepInPlugin("com.odinthewise.odinsreclaim", "OdinsReclaim", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony _harmony; private float _nextErrorLog; private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Settings.Bind(((BaseUnityPlugin)this).Config); GuiAccess.Init(); _harmony = new Harmony("com.odinthewise.odinsreclaim"); _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"OdinsReclaim 1.0.0 loaded"); } private void Update() { Banner.Tick(); try { InventoryKeys.Tick(); } catch (Exception ex) { if (!(Time.unscaledTime < _nextErrorLog)) { _nextErrorLog = Time.unscaledTime + 10f; Log.LogError((object)("Inventory keys failed (check the keys in F1): " + ex)); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void Say(Player p, string text, bool always = false) { if (Object.op_Implicit((Object)(object)p) && (always || Settings.ShowReasons.Value) && !Banner.Show(text)) { ((Character)p).Message((MessageType)2, text, 0, (Sprite)null, false); } } internal static string UndoHint() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (Settings.UndoSeconds.Value <= 0) { return ""; } KeyboardShortcut value = Settings.UndoShortcut.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0) { return " (" + Settings.ShortcutText(value) + " to undo)"; } return ""; } } [HarmonyPatch] internal static class ReclaimTab { private static Button s_tab; private static bool s_hooked; private static float s_nextPress; private const float PressCooldown = 0.4f; internal static bool Active { get; private set; } [HarmonyPatch(typeof(InventoryGui), "Awake")] [HarmonyPostfix] private static void AfterAwake(InventoryGui __instance) { Active = false; if (!GuiAccess.Ok || !Object.op_Implicit((Object)(object)__instance.m_tabUpgrade) || !Object.op_Implicit((Object)(object)__instance.m_tabCraft)) { return; } try { s_tab = GuiAccess.CloneButton(__instance.m_tabUpgrade, "OdinsReclaim_Tab", "Reclaim", delegate { Open(__instance); }); UITooltip component = ((Component)s_tab).GetComponent<UITooltip>(); if (Object.op_Implicit((Object)(object)component)) { component.m_text = "Break items back into materials"; } Place(__instance); if (!s_hooked) { s_hooked = true; Settings.TabOffset.SettingChanged += delegate { Place(InventoryGui.instance); }; } ((Component)s_tab).gameObject.SetActive(false); } catch (Exception ex) { Plugin.Log.LogError((object)("Couldn't add the Reclaim tab: " + ex)); s_tab = null; } } private static void Place(InventoryGui gui) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)gui) && Object.op_Implicit((Object)(object)s_tab)) { RectTransform val = (RectTransform)((Component)gui.m_tabUpgrade).transform; RectTransform val2 = (RectTransform)((Component)gui.m_tabCraft).transform; ((RectTransform)((Component)s_tab).transform).anchoredPosition = val.anchoredPosition + (val.anchoredPosition - val2.anchoredPosition) + Settings.TabOffset.Value; } } private static bool Allowed(Player p) { if (!Object.op_Implicit((Object)(object)p) || !Object.op_Implicit((Object)(object)s_tab) || !GuiAccess.Ok || !Settings.TabEnabled.Value) { return false; } CraftingStation currentCraftingStation = p.GetCurrentCraftingStation(); if (Object.op_Implicit((Object)(object)currentCraftingStation)) { return currentCraftingStation.m_hasCraftTab; } return false; } private static void Open(InventoryGui gui) { if (Object.op_Implicit((Object)(object)gui) && Allowed(Player.m_localPlayer)) { Active = true; ((Selectable)gui.m_tabCraft).interactable = true; ((Selectable)gui.m_tabUpgrade).interactable = true; ((Selectable)s_tab).interactable = false; GuiAccess.RefreshCrafting(gui); } } private static void Leave(InventoryGui gui) { Active = false; ((Selectable)gui.m_tabCraft).interactable = false; ((Selectable)gui.m_tabUpgrade).interactable = true; if (Object.op_Implicit((Object)(object)s_tab)) { ((Selectable)s_tab).interactable = true; } } [HarmonyPatch(typeof(InventoryGui), "OnTabCraftPressed")] [HarmonyPrefix] private static void BeforeCraftTab() { LeftByVanillaTab(); } [HarmonyPatch(typeof(InventoryGui), "OnTabUpgradePressed")] [HarmonyPrefix] private static void BeforeUpgradeTab() { LeftByVanillaTab(); } private static void LeftByVanillaTab() { Active = false; if (Object.op_Implicit((Object)(object)s_tab)) { ((Selectable)s_tab).interactable = true; } } [HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")] [HarmonyPrefix] private static void BeforeCraftingPanel(InventoryGui __instance) { if (Object.op_Implicit((Object)(object)s_tab)) { bool flag = Allowed(Player.m_localPlayer); if (!flag && Active) { Leave(__instance); } ((Component)s_tab).gameObject.SetActive(flag); ((Selectable)s_tab).interactable = !Active; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] [HarmonyPrefix] private static bool BeforeRecipeList(InventoryGui __instance) { if (!Active) { return true; } try { BuildList(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Reclaim list failed: " + ex)); } return false; } private static void BuildList(InventoryGui gui) { GuiAccess.ClearList(gui); Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); List<Plan> list = new List<Plan>(); foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if ((Settings.TabHideEquipped.Value && allItem.m_equipped) || (Settings.TabHideHotbar.Value && allItem.m_gridPos.y == 0) || allItem.m_shared.m_questItem || (Settings.IsExcluded(allItem) && !Settings.IsAlwaysAllowed(allItem))) { continue; } Recipe val = Yields.FindRecipe(allItem); if (Object.op_Implicit((Object)(object)val) && val.m_enabled && !val.m_requireOnlyOneIngredient && (!Object.op_Implicit((Object)(object)val.m_craftingStation) || !Settings.IsExcludedStation(((Object)((Component)val.m_craftingStation).gameObject).name))) { CraftingStation requiredStation = val.GetRequiredStation(Mathf.Clamp(allItem.m_quality, 1, Mathf.Max(1, allItem.m_shared.m_maxQuality))); if (!Settings.NeedStation.Value || !Object.op_Implicit((Object)(object)requiredStation) || (Object.op_Implicit((Object)(object)currentCraftingStation) && !(requiredStation.m_name != currentCraftingStation.m_name))) { list.Add(Yields.Make(allItem, localPlayer, Way.Tab, currentCraftingStation)); } } } list.Sort(delegate(Plan a, Plan b) { int num = b.Ok.CompareTo(a.Ok); if (num == 0) { num = string.Compare(Localization.instance.Localize(a.Source.m_shared.m_name), Localization.instance.Localize(b.Source.m_shared.m_name), StringComparison.CurrentCulture); } if (num == 0) { num = b.Source.m_quality.CompareTo(a.Source.m_quality); } return num; }); foreach (Plan item in list) { GuiAccess.AddToList(gui, localPlayer, item.Recipe, item.Source, item.Ok); GameObject obj = GuiAccess.LastElement(gui); object obj2; if (obj == null) { obj2 = null; } else { Transform obj3 = obj.transform.Find("name"); obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null); } TMP_Text val2 = (TMP_Text)obj2; if (Object.op_Implicit((Object)(object)val2)) { val2.text = Localization.instance.Localize(item.Source.m_shared.m_name) + ((item.Source.m_stack > 1) ? (" x" + item.Source.m_stack) : ""); } } GuiAccess.SizeList(gui); } [HarmonyPatch(typeof(InventoryGui), "SetupRequirementList")] [HarmonyPrefix] private static bool BeforeRequirementList() { return !Active; } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")] [HarmonyPostfix] private static void AfterRecipe(InventoryGui __instance, Player player) { if (!Active) { return; } try { if (!Allowed(player)) { Leave(__instance); GuiAccess.RefreshCrafting(__instance); } else { ShowSelected(__instance, player); } } catch (Exception ex) { Plugin.Log.LogError((object)("Reclaim panel failed, back to the Craft tab: " + ex)); Leave(__instance); } } private static void ShowSelected(InventoryGui gui, Player player) { //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) GuiAccess.Selected(gui, out var recipe, out var item); TMP_Text componentInChildren = ((Component)gui.m_craftButton).GetComponentInChildren<TMP_Text>(); if (Object.op_Implicit((Object)(object)componentInChildren)) { componentInChildren.text = "Reclaim"; } if (Object.op_Implicit((Object)(object)gui.m_variantButton)) { ((Component)gui.m_variantButton).gameObject.SetActive(false); } UITooltip component = ((Component)gui.m_craftButton).GetComponent<UITooltip>(); Inventory inventory = ((Humanoid)player).GetInventory(); if (!Object.op_Implicit((Object)(object)recipe) || item == null || !inventory.ContainsItem(item)) { ((Selectable)gui.m_craftButton).interactable = false; if (Object.op_Implicit((Object)(object)component)) { component.m_text = ""; } if (Object.op_Implicit((Object)(object)gui.m_itemCraftType)) { ((Component)gui.m_itemCraftType).gameObject.SetActive(false); } ShowOutputs(gui, null); return; } Plan plan = Yields.Make(item, player, Way.Tab, player.GetCurrentCraftingStation()); bool flag = plan.Ok && Moves.Fits(inventory, plan.Outputs, 1); string text = ((!plan.Ok) ? plan.Problem : (flag ? null : "not enough room in your inventory for the materials")); string text2 = Localization.instance.Localize(item.m_shared.m_name); if (item.m_stack > 1) { text2 = text2 + " x" + item.m_stack; } gui.m_recipeName.text = text2; gui.m_recipeIcon.sprite = item.GetIcon(); float num = Settings.RateFor(item, Settings.Rate.Value); if (item.m_shared.m_maxStackSize > 1) { num = Mathf.Min(num, Settings.StackRateCap.Value); } string text3 = $"<color=orange>Reclaim: get back {Mathf.RoundToInt(num * 100f)}% of what it took to make" + ((item.m_quality > 1) ? $" and upgrade it to level {item.m_quality}" : "") + ".</color>"; if (text != null) { text3 = text3 + "\n<color=red>Can't reclaim: " + text + ".</color>"; } gui.m_recipeDecription.text = text3 + "\n\n" + Localization.instance.Localize(ItemData.GetTooltip(item, item.m_quality, false, (float)Game.m_worldLevel, -1, false)); if (Object.op_Implicit((Object)(object)gui.m_itemCraftType)) { ((Component)gui.m_itemCraftType).gameObject.SetActive(true); gui.m_itemCraftType.text = ((text == null) ? "Reclaim" : "Can't reclaim"); } if (Object.op_Implicit((Object)(object)gui.m_minStationLevelIcon)) { bool flag2 = Object.op_Implicit((Object)(object)plan.NeedStation) && plan.NeedLevel > 1; ((Component)gui.m_minStationLevelIcon).gameObject.SetActive(flag2); if (flag2 && Object.op_Implicit((Object)(object)gui.m_minStationLevelText)) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); gui.m_minStationLevelText.text = plan.NeedLevel.ToString(); ((Graphic)gui.m_minStationLevelText).color = ((Object.op_Implicit((Object)(object)currentCraftingStation) && currentCraftingStation.GetLevel(true) >= plan.NeedLevel) ? Color.white : Color.red); } } ShowOutputs(gui, plan.Ok ? plan.Outputs : null); ((Selectable)gui.m_craftButton).interactable = text == null && GuiAccess.CraftTimer(gui) < 0f; if (Object.op_Implicit((Object)(object)component)) { component.m_text = text ?? ""; } } private static void ShowOutputs(InventoryGui gui, List<Output> outputs) { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) GameObject[] recipeRequirementList = gui.m_recipeRequirementList; int num = outputs?.Count ?? 0; int num2 = 0; if (num > recipeRequirementList.Length && recipeRequirementList.Length != 0) { int num3 = (num + recipeRequirementList.Length - 1) / recipeRequirementList.Length; num2 = (int)Time.fixedTime % num3 * recipeRequirementList.Length; } for (int i = 0; i < recipeRequirementList.Length; i++) { Transform transform = recipeRequirementList[i].transform; Transform obj = transform.Find("res_icon"); Image val = ((obj != null) ? ((Component)obj).GetComponent<Image>() : null); Transform obj2 = transform.Find("res_name"); TMP_Text val2 = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null); Transform obj3 = transform.Find("res_amount"); TMP_Text val3 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null); UITooltip component = ((Component)transform).GetComponent<UITooltip>(); int num4 = num2 + i; bool flag = num4 < num; if (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.SetActive(flag); } if (Object.op_Implicit((Object)(object)val2)) { ((Component)val2).gameObject.SetActive(flag); } if (Object.op_Implicit((Object)(object)val3)) { ((Component)val3).gameObject.SetActive(flag); } if (!flag) { if (Object.op_Implicit((Object)(object)component)) { component.m_text = ""; } continue; } Output output = outputs[num4]; string text = Localization.instance.Localize(output.Name); if (Object.op_Implicit((Object)(object)val)) { val.sprite = output.Item.m_itemData.GetIcon(); ((Graphic)val).color = Color.white; } if (Object.op_Implicit((Object)(object)val2)) { val2.text = text; } if (Object.op_Implicit((Object)(object)val3)) { val3.text = "+" + output.Amount; ((Graphic)val3).color = Color.green; } if (Object.op_Implicit((Object)(object)component)) { component.m_text = text; } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] [HarmonyPrefix] private static bool BeforeCraftPressed(InventoryGui __instance) { if (!Active) { return true; } try { ReclaimSelected(__instance); } catch (Exception ex) { Plugin.Log.LogError((object)("Reclaim failed: " + ex)); } return false; } private static void ReclaimSelected(InventoryGui gui) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || GuiAccess.CraftTimer(gui) >= 0f || Time.unscaledTime < s_nextPress) { return; } s_nextPress = Time.unscaledTime + 0.4f; GuiAccess.Selected(gui, out var _, out var item); if (item == null) { return; } Inventory inventory = ((Humanoid)localPlayer).GetInventory(); CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); Plan plan = Yields.Make(item, localPlayer, Way.Tab, currentCraftingStation); if (!plan.Ok) { Plugin.Say(localPlayer, "Can't reclaim: " + plan.Problem); return; } if (!Moves.Fits(inventory, plan.Outputs, 1)) { Plugin.Say(localPlayer, "Not enough room in your inventory for the materials"); return; } string text = Localization.instance.Localize(item.m_shared.m_name); ItemData val = Moves.Take(inventory, item, (Humanoid)(object)localPlayer); if (val == null) { GuiAccess.RefreshCrafting(gui); return; } Undo.Entry e = Undo.Record(localPlayer, inventory, new List<ItemData> { val }, plan.Outputs, "reclaimed " + text); int num; try { num = Moves.Give(inventory, plan.Outputs, val.m_cheated, Moves.Feet(localPlayer), localPlayer); } catch (Exception arg) { Undo.Forget(e); Moves.PutBack(inventory, val, Moves.Feet(localPlayer)); Plugin.Log.LogError((object)$"Reclaiming {text} failed half-way, the item was put back: {arg}"); Plugin.Say(localPlayer, "Something went wrong; " + text + " was put back", always: true); Refresh(gui); return; } if (num > 0) { Undo.Forget(e); } if (Object.op_Implicit((Object)(object)currentCraftingStation)) { currentCraftingStation.m_craftItemDoneEffects.Create(((Component)localPlayer).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } Plugin.Say(localPlayer, "Reclaimed " + text + ": " + plan.OutputText() + ((num > 0) ? " (some fell at your feet)" : Plugin.UndoHint()), always: true); if (Settings.LogActions.Value) { Plugin.Log.LogInfo((object)($"Reclaim tab: {Yields.PrefabName(val)} q{val.m_quality} x{val.m_stack} -> {plan.OutputText()}" + ((num > 0) ? $" ({num} dropped)" : ""))); } Refresh(gui); } private static void Refresh(InventoryGui gui) { GuiAccess.RefreshCrafting(gui); GuiAccess.ClearSelection(gui); } } internal static class Settings { internal static ConfigEntry<float> Rate; internal static ConfigEntry<string> RateOverrides; internal static ConfigEntry<string> ExcludeItems; internal static ConfigEntry<string> ExcludeStations; internal static ConfigEntry<bool> AllowUnknownRecipes; internal static ConfigEntry<bool> AtLeastOne; internal static ConfigEntry<bool> ProtectEnchanted; internal static ConfigEntry<bool> NeedStationLevel; internal static ConfigEntry<float> StackRateCap; internal static ConfigEntry<string> AlwaysAllow; internal static ConfigEntry<string> CustomGroups; internal static ConfigEntry<bool> NeedStation; internal static ConfigEntry<bool> EpicLootRefund; internal static ConfigEntry<bool> ApplyCrafter; internal static ConfigEntry<bool> TabEnabled; internal static ConfigEntry<bool> TabHideEquipped; internal static ConfigEntry<bool> TabHideHotbar; internal static ConfigEntry<Vector2> TabOffset; internal static ConfigEntry<bool> ChestEnabled; internal static ConfigEntry<Vector2> ChestButtonPos; internal static ConfigEntry<bool> ChestSingleOnly; internal static ConfigEntry<string> ChestRules; internal static ConfigEntry<bool> KeyEnabled; internal static ConfigEntry<bool> KeyAdminsOnly; internal static ConfigEntry<float> KeyRate; internal static ConfigEntry<bool> KeyRefundUnknown; internal static ConfigEntry<KeyboardShortcut> KeyShortcut; internal static ConfigEntry<bool> TrashEnabled; internal static ConfigEntry<KeyCode> TrashHoldKey; internal static ConfigEntry<KeyCode> TrashDeleteKey; internal static ConfigEntry<Color> TrashColor; internal static ConfigEntry<bool> TrashCanEnabled; internal static ConfigEntry<bool> TrashCanConfirm; internal static ConfigEntry<Vector2> TrashCanOffset; internal static ConfigEntry<int> UndoSeconds; internal static ConfigEntry<KeyboardShortcut> UndoShortcut; internal static ConfigEntry<bool> ShowReasons; internal static ConfigEntry<bool> TooltipYield; internal static ConfigEntry<bool> LogActions; internal static ConfigEntry<Vector2> BannerOffset; internal static ConfigEntry<bool> ShowKeyHints; internal static ConfigEntry<Vector2> KeyHintsOffset; private const string GroupNote = " Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups."; private static List<string> s_itemCache; private static List<string> s_allowCache; private static HashSet<string> s_stationCache; private static List<KeyValuePair<string, float>> s_rateCache; private static Dictionary<string, List<string>> s_chestCache; public static void Bind(ConfigFile cfg) { //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) Rate = Synced(cfg, "1 - Rules", "Return rate", 0.5f, "Share of the materials you get back when you reclaim at a crafting station (Reclaim tab and the chest button). 0.5 = half. Amounts round down. Upgraded items give back their upgrade materials too.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f)); RateOverrides = Synced(cfg, "1 - Rules", "Return rate per item", "", "Optional rates for items or groups: SwordIron=1, Armor=0.75. They replace the return rate for those items (every way of reclaiming). An item's own name wins over a group; otherwise the first matching group counts. Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups."); ExcludeItems = Synced(cfg, "1 - Rules", "Never reclaim these items", "", "Items or groups, separated by commas (for example: Hammer, Hoe, Tools, Metals). These are never broken down. The Delete key and the trash can still delete them, without giving anything back. Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups."); AlwaysAllow = Synced(cfg, "1 - Rules", "Always allow these items", "", "Items or groups that may always be reclaimed, even when the never list or a chest rule covers them (for example: never Armor, but always ArmorBronzeChest). Groups: All, Food, Potion, Fish, Swords, Axes, Clubs, Knives, Pickaxes, Polearms, Spears, Bows, Crossbows, Shields, Armor, Helmets, Ammunition, Utilities, Trinkets, Tools, Equipment, Trophy, Boss Trophy, Materials, Ores, Metals, Woods, Seeds, Crops, Miscellaneous, Customizations, and your custom groups."); CustomGroups = Synced(cfg, "1 - Rules", "Custom groups", "", "Your own groups for the lists above, separated by semicolons: Tier 2 = Bronze, PickaxeBronze, ArmorBronzeChest; Starter = Club, Torch. A group may name other groups."); ExcludeStations = Synced(cfg, "1 - Rules", "Never reclaim items made at", "piece_cauldron, piece_preptable, piece_MeadCauldron", "Crafting stations by prefab name; everything made there is left alone (by default food and meads). Others: piece_workbench, forge, piece_stonecutter, piece_artisanstation, blackforge, piece_magetable."); AllowUnknownRecipes = Synced(cfg, "1 - Rules", "Allow items whose recipe you do not know", def: false, "Off: you can only reclaim items you could craft yourself (you know the recipe). On: any item with a recipe."); AtLeastOne = Synced(cfg, "1 - Rules", "Single items give back at least 1 of each material", def: true, "A non-stacking item (weapon, armour, tool) gives at least 1 of every material in its recipe, even when the return rate rounds it down to 0."); ProtectEnchanted = Synced(cfg, "1 - Rules", "Protect Epic Loot items", def: false, "On: items enchanted with Epic Loot are never reclaimed, and the Delete key and trash can won't delete them (trash marking still does, on purpose). Off: they can be reclaimed like any item."); EpicLootRefund = Synced(cfg, "1 - Rules", "Epic Loot: give back enchanting materials", def: true, "Reclaiming an item enchanted with Epic Loot also gives back what enchanting it at its rarity costs (Epic Loot's own enchant costs), at the same return rate. Off: only the item's recipe comes back."); NeedStation = Synced(cfg, "1 - Rules", "Need the right crafting station", def: true, "On: the Reclaim tab only shows items made at the station you are using, and Reclaim all needs that station nearby. Off: crafting stations don't matter at all."); ApplyCrafter = Synced(cfg, "1 - Rules", "You are the crafter of returned materials", def: true, "On: materials you get back carry your name as their crafter. Off: no crafter, like picked-up materials."); NeedStationLevel = Synced(cfg, "1 - Rules", "Need the station level the item needs", def: true, "On: reclaiming an item needs the sam