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 ChestSalvage v1.0.0
ChestSalvage.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace ChestSalvage; public static class SalvageMath { public static int Refund(int baseCost, int[] upgradeCosts, float baseRate, float upgradeRate) { int num = 0; foreach (int val in upgradeCosts) { num += Math.Max(val, 0); } return Scale(Math.Max(baseCost, 0), baseRate) + Scale(num, upgradeRate); } public static bool PaidOnCraft(bool upgraderResource) { return !upgraderResource; } public static int[] PaidUpgradeLevels(int quality, int maxQuality, bool upgraderResource) { int num = (upgraderResource ? (Math.Max(maxQuality, 1) + 1) : 2); int num2 = (upgraderResource ? quality : Math.Min(quality, maxQuality)); if (num2 < num) { return new int[0]; } int[] array = new int[num2 - num + 1]; for (int i = 0; i < array.Length; i++) { array[i] = num + i; } return array; } private static int Scale(int amount, float rate) { float num = Math.Max(0f, Math.Min(rate, 1f)); return (int)Math.Ceiling(Math.Round((float)amount * num, 4)); } } [BepInPlugin("com.parallel53.chestsalvage", "Chest Salvage", "1.0.0")] public class ChestSalvagePlugin : BaseUnityPlugin { private const float RefreshSeconds = 0.5f; private const int MaxPreviewLines = 8; private static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer"); private static readonly HashSet<ItemType> GearTypes = new HashSet<ItemType> { (ItemType)3, (ItemType)14, (ItemType)22, (ItemType)4, (ItemType)5, (ItemType)6, (ItemType)7, (ItemType)11, (ItemType)12, (ItemType)17, (ItemType)18, (ItemType)19, (ItemType)24 }; private static ConfigEntry<float> baseRate; private static ConfigEntry<float> upgradeRate; private static ConfigEntry<bool> requireStation; private static Button button; private static TMP_Text label; private static float nextRefresh; private void Awake() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) baseRate = ((BaseUnityPlugin)this).Config.Bind<float>("Salvage", "BaseReturnRate", 0.5f, new ConfigDescription("Share of the crafting cost returned, rounded up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); upgradeRate = ((BaseUnityPlugin)this).Config.Bind<float>("Salvage", "UpgradeReturnRate", 1f, new ConfigDescription("Share of the upgrade costs returned, rounded up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); requireStation = ((BaseUnityPlugin)this).Config.Bind<bool>("Salvage", "RequireStation", true, "Only salvage an item when the crafting station its recipe uses is in range."); new Harmony("com.parallel53.chestsalvage").PatchAll(typeof(ChestSalvagePlugin)); } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "Awake")] private static void AddButton(InventoryGui __instance) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_011a: 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_0135: Unknown result type (might be due to invalid IL or missing references) Button takeAllButton = __instance.m_takeAllButton; button = Object.Instantiate<Button>(takeAllButton, ((Component)takeAllButton).transform.parent); ((Object)button).name = "ChestSalvageButton"; button.onClick = new ButtonClickedEvent(); ((UnityEvent)button.onClick).AddListener(new UnityAction(OnClick)); UIGamePad[] componentsInChildren = ((Component)button).GetComponentsInChildren<UIGamePad>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } Localize[] componentsInChildren2 = ((Component)button).GetComponentsInChildren<Localize>(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } label = ((Component)button).GetComponentInChildren<TMP_Text>(true); RectTransform val = (RectTransform)((Component)takeAllButton).transform; RectTransform val2 = (RectTransform)((Component)button).transform; val2.anchorMin = new Vector2(0.5f, val2.anchorMin.y); val2.anchorMax = new Vector2(0.5f, val2.anchorMax.y); val2.pivot = new Vector2(0.5f, val2.pivot.y); val2.anchoredPosition = new Vector2(0f, val.anchoredPosition.y); } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "Update")] private static void RefreshButton(InventoryGui __instance) { if (!((Object)(object)button == (Object)null) && !(Time.unscaledTime < nextRefresh)) { nextRefresh = Time.unscaledTime + 0.5f; Container val = CurrentContainer.Invoke(__instance); bool flag = (Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent<TombStone>() == (Object)null; if (((Component)button).gameObject.activeSelf != flag) { ((Component)button).gameObject.SetActive(flag); } if (flag) { label.text = "Salvage (" + Salvageable(val.GetInventory()).Count + ")"; } } } private static List<ItemData> Salvageable(Inventory inventory) { return inventory.GetAllItems().Where(CanSalvage).ToList(); } private static bool CanSalvage(ItemData item) { if (IsGear(item)) { return StationInRange(item); } return false; } private static bool IsGear(ItemData item) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!GearTypes.Contains(item.m_shared.m_itemType) || item.m_shared.m_questItem) { return false; } Recipe recipe = ObjectDB.instance.GetRecipe(item); if ((Object)(object)recipe != (Object)null && recipe.m_enabled && recipe.m_amount == 1) { return !recipe.m_requireOnlyOneIngredient; } return false; } private static CraftingStation RequiredStation(ItemData item) { return ObjectDB.instance.GetRecipe(item).GetRequiredStation(1); } private static bool StationInRange(ItemData item) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) CraftingStation val = RequiredStation(item); if (requireStation.Value && !((Object)(object)val == (Object)null)) { return (Object)(object)CraftingStation.HaveBuildStationInRange(val.m_name, ((Component)Player.m_localPlayer).transform.position) != (Object)null; } return true; } private static string NothingToSalvageMessage(Inventory inventory) { string[] array = (from item in inventory.GetAllItems() where IsGear(item) && !StationInRange(item) select Localization.instance.Localize(RequiredStation(item).m_name)).Distinct().ToArray(); if (array.Length != 0) { return "Salvaging this gear needs a nearby " + string.Join(" or ", array); } return "Nothing to salvage in this chest"; } private static Dictionary<ItemDrop, int> Refunds(List<ItemData> items) { Dictionary<ItemDrop, int> dictionary = new Dictionary<ItemDrop, int>(); foreach (ItemData item in items) { Requirement[] resources = ObjectDB.instance.GetRecipe(item).m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val.m_resItem == (Object)null)) { bool upgraderResource = val.m_upgraderResource; int[] upgradeCosts = ((IEnumerable<int>)SalvageMath.PaidUpgradeLevels(item.m_quality, item.m_shared.m_maxQuality, upgraderResource)).Select((Func<int, int>)val.GetAmount).ToArray(); int num = SalvageMath.Refund(SalvageMath.PaidOnCraft(upgraderResource) ? val.GetAmount(1) : 0, upgradeCosts, baseRate.Value, upgradeRate.Value); if (num > 0) { dictionary.TryGetValue(val.m_resItem, out var value); dictionary[val.m_resItem] = value + num; } } } } return dictionary; } private static void OnClick() { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00c6: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Expected O, but got Unknown Container container = CurrentContainer.Invoke(InventoryGui.instance); if ((Object)(object)container == (Object)null || UnifiedPopup.IsVisible()) { return; } List<ItemData> list = Salvageable(container.GetInventory()); if (list.Count == 0) { ((Character)Player.m_localPlayer).Message((MessageType)2, NothingToSalvageMessage(container.GetInventory()), 0, (Sprite)null, false); return; } UnifiedPopup.Push((PopupBase)new YesNoPopup("Salvage " + list.Count + ((list.Count == 1) ? " item" : " items") + "?", Preview(Refunds(list)), (PopupButtonCallback)delegate { UnifiedPopup.Pop(); Salvage(container); }, new PopupButtonCallback(UnifiedPopup.Pop), false, false)); } private static string Preview(Dictionary<ItemDrop, int> refunds) { List<string> list = (from pair in refunds orderby pair.Value descending select pair.Value + " " + Localization.instance.Localize(pair.Key.m_itemData.m_shared.m_name)).ToList(); if (list.Count == 0) { return "These items return no materials and will be destroyed."; } int num = list.Count - 8; IEnumerable<string> source = list.Take(8); string text = string.Join("\n", source.ToArray()); return "You get:\n" + text + ((num > 0) ? ("\n+ " + num + " more") : ""); } private static void Salvage(Container container) { if ((Object)(object)container == (Object)null || (Object)(object)CurrentContainer.Invoke(InventoryGui.instance) != (Object)(object)container) { return; } Inventory inventory = container.GetInventory(); List<ItemData> list = Salvageable(inventory); Dictionary<ItemDrop, int> dictionary = Refunds(list); Debug.Log((object)("Chest Salvage: salvaged " + string.Join(", ", list.Select((ItemData i) => i.m_shared.m_name + " q" + i.m_quality).ToArray()) + " for " + string.Join(", ", dictionary.Select((KeyValuePair<ItemDrop, int> r) => r.Value + " " + ((Object)r.Key).name).ToArray()))); foreach (ItemData item in list) { inventory.RemoveItem(item); } foreach (KeyValuePair<ItemDrop, int> item2 in dictionary) { Give(item2.Key, item2.Value, inventory); } nextRefresh = 0f; } private static void Give(ItemDrop item, int amount, Inventory chest) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00a8: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; int num = Mathf.Max(item.m_itemData.m_shared.m_maxStackSize, 1); while (amount > 0) { int num2 = Mathf.Min(amount, num); amount -= num2; if (chest.CanAddItem(((Component)item).gameObject, num2)) { chest.AddItem(((Component)item).gameObject, num2); } else if (((Humanoid)localPlayer).GetInventory().CanAddItem(((Component)item).gameObject, num2)) { ((Humanoid)localPlayer).GetInventory().AddItem(((Component)item).gameObject, num2); } else { ItemDrop.DropItem(item.m_itemData.Clone(), num2, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward + Vector3.up, Quaternion.identity); } } } }