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 EpicLootStorageMaterials v1.2.0
EpicLootStorageMaterials.dll
Decompiled 6 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EpicLoot_UnityLib; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")] [assembly: AssemblyCompany("EpicLootStorageMaterials")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EpicLootStorageMaterials")] [assembly: AssemblyTitle("EpicLootStorageMaterials")] [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 EpicLootStorageMaterials { [BepInPlugin("pieter.valheim.epiclootstoragematerials", "Epic Loot Storage Materials", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(Container), "Awake")] private static class ContainerRegistry { private static void Postfix(Container __instance) { Containers.Add(__instance); } } [HarmonyPatch(typeof(SacrificeUI), "SacrificeItems")] private static class SacrificePatch { private static void Prefix() { Sacrificed.Clear(); if (_perItemDouble.Value && !(ProductsMethod == null) && !(GiveMethod == null)) { EnchantingTableUI instance = EnchantingTableUI.instance; EnchantingTable val = ((instance != null) ? instance.SourceTable : null); if (!((Object)(object)val == (Object)null)) { Tuple<float, float> featureCurrentValue = val.GetFeatureCurrentValue((EnchantingFeature)0); _doubleChance = (float.IsNaN(featureCurrentValue.Item1) ? 0f : (featureCurrentValue.Item1 / 100f)); _sacrificing = true; } } } private static void Postfix(SacrificeUI __instance) { if (!_sacrificing) { return; } _sacrificing = false; List<Tuple<ItemData, int>> list = new List<Tuple<ItemData, int>>(); foreach (Tuple<ItemData, int> item in Sacrificed) { int num = 0; for (int i = 0; i < item.Item2; i++) { if (Random.value < _doubleChance) { num++; } } if (num > 0) { list.Add(Tuple.Create<ItemData, int>(item.Item1, num)); } } if (list.Count != 0) { object obj = ProductsMethod.Invoke(null, new object[1] { list }); EnchantingTableUI instance = EnchantingTableUI.instance; if (instance != null) { instance.PlayEnchantBonusSFX(); } if ((Object)(object)__instance.BonusPanel != (Object)null) { __instance.BonusPanel.Show(); } GiveMethod.Invoke(null, new object[1] { obj }); RefreshSacrifice?.Invoke(__instance, null); } } private static Exception Finalizer(Exception __exception) { _sacrificing = false; return __exception; } } [HarmonyPatch(typeof(EnchantingTable), "GetFeatureCurrentValue")] private static class FeatureValuePatch { private static void Postfix(EnchantingFeature feature, ref Tuple<float, float> __result) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (_sacrificing && (int)feature == 0) { __result = Tuple.Create(float.NaN, float.NaN); } } } [HarmonyPatch(typeof(InventoryManagement), "RemoveExactItem")] private static class RemovedPatch { private static void Postfix(ItemData item, int __result) { if (_sacrificing && item != null && __result > 0) { Sacrificed.Add(Tuple.Create<ItemData, int>(item, __result)); } } } [HarmonyPatch(typeof(SacrificeUI), "OnEnable")] private static class ChestToggleUi { private static void Postfix(SacrificeUI __instance) { //IL_0076: 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_0088: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown try { Toggle val = ((EnchantingTableUIPanelBase)__instance).AvailableItems?.SelectAllToggle; if ((Object)(object)val == (Object)null) { return; } Transform parent = ((Component)val).transform.parent; if (!((Object)(object)parent.Find("IncludeChestsToggle") != (Object)null)) { GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, parent, false); ((Object)val2).name = "IncludeChestsToggle"; RectTransform val3 = (RectTransform)val2.transform; RectTransform val4 = (RectTransform)((Component)val).transform; Vector2 anchoredPosition = val4.anchoredPosition; Rect rect = val4.rect; val3.anchoredPosition = anchoredPosition + new Vector2(0f, ((Rect)(ref rect)).height + 4f); Text[] componentsInChildren = val2.GetComponentsInChildren<Text>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].text = "Include chests"; } Toggle component = val2.GetComponent<Toggle>(); component.onValueChanged = new ToggleEvent(); component.SetIsOnWithoutNotify(_trophies.Value); ((Selectable)component).interactable = true; ((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool on) { _trophies.Value = on; RefreshSacrifice?.Invoke(__instance, null); }); } } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Could not add the Include chests toggle: " + ex.Message)); } } } } public const string Guid = "pieter.valheim.epiclootstoragematerials"; public const string Name = "Epic Loot Storage Materials"; public const string Version = "1.2.0"; private const string EpicLootGuid = "randyknapp.mods.epicloot"; private const string ProviderId = "pieter.nearbychests"; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _trophies; private static ConfigEntry<bool> _perItemDouble; private static ManualLogSource _log; private static ConfigEntry<float> _range; private static readonly HashSet<Container> Containers = new HashSet<Container>(); private static MethodInfo _checkAccess; [ThreadStatic] private static bool _sacrificing; private static float _doubleChance; private static readonly List<Tuple<ItemData, int>> Sacrificed = new List<Tuple<ItemData, int>>(); private static readonly MethodInfo ProductsMethod = AccessTools.Method(AccessTools.TypeByName("EpicLoot.CraftingV2.EnchantingUIController"), "GetSacrificeProducts", new Type[1] { typeof(List<Tuple<ItemData, int>>) }, (Type[])null); private static readonly MethodInfo GiveMethod = AccessTools.Method(typeof(EnchantingTableUIPanelBase), "GiveItemsToPlayer", (Type[])null, (Type[])null); private static readonly MethodInfo RefreshSacrifice = AccessTools.Method(typeof(SacrificeUI), "RefreshAvailableItems", (Type[])null, (Type[])null); private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0126: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) _enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Use materials from nearby chests for Epic Loot enchanting table costs."); _range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range (m)", 50f, new ConfigDescription("How far from you chests are used.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>())); _trophies = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Chest trophies in Sacrifice", true, "List trophies from nearby chests in the enchanting table's Sacrifice tab; sacrificing takes them from the chest. Also switchable with the Include chests checkbox in the Sacrifice tab."); _perItemDouble = ((BaseUnityPlugin)this).Config.Bind<bool>("Sacrifice", "Roll double output per item", true, "Roll the enchanting table's double-output chance for every sacrificed item instead of once for the whole batch (all doubled or nothing). Same average, but large batches give anything between 1x and 2x."); _log = ((BaseUnityPlugin)this).Logger; _checkAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); Type type = AccessTools.TypeByName("EpicLoot.API"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "RegisterInventoryProvider", (Type[])null, (Type[])null)); if (methodInfo == null || _checkAccess == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"Disabled, Epic Loot's inventory provider API or Container.CheckAccess was not found."); return; } Harmony val = new Harmony("pieter.valheim.epiclootstoragematerials"); val.PatchAll(typeof(ContainerRegistry)); val.PatchAll(typeof(SacrificePatch)); val.PatchAll(typeof(FeatureValuePatch)); val.PatchAll(typeof(RemovedPatch)); val.PatchAll(typeof(ChestToggleUi)); bool flag = (bool)methodInfo.Invoke(null, new object[5] { "pieter.nearbychests", new Func<List<ItemData>>(ChestTrophies), new Func<string, int>(CountItem), new Func<string, int, int>(RemoveItem), new Func<ItemData, int, int>(RemoveExactItem) }); ((BaseUnityPlugin)this).Logger.LogInfo((object)(flag ? "Epic Loot can now use materials from nearby chests." : "Epic Loot refused the inventory provider.")); } private static IEnumerable<Container> UsableChests() { Player player = Player.m_localPlayer; if (!_enabled.Value || (Object)(object)player == (Object)null) { yield break; } Vector3 origin = ((Component)player).transform.position; float maxSqr = _range.Value * _range.Value; Containers.RemoveWhere((Container c) => (Object)(object)c == (Object)null); foreach (Container item in Containers.OrderBy(delegate(Container c) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val2 = ((Component)c).transform.position - origin; return ((Vector3)(ref val2)).sqrMagnitude; })) { Vector3 val = ((Component)item).transform.position - origin; if (((Vector3)(ref val)).sqrMagnitude > maxSqr) { break; } if (IsUsable(item, player)) { yield return item; } } } private static bool IsUsable(Container chest, Player player) { if (!((Behaviour)chest).isActiveAndEnabled || chest.GetInventory() == null) { return false; } Piece componentInParent = ((Component)chest).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsPlacedByPlayer()) { return false; } if ((Object)(object)chest.m_wagon != (Object)null || (Object)(object)((Component)chest).GetComponentInParent<Ship>() != (Object)null) { return false; } if (!chest.IsOwner() || chest.IsInUse()) { return false; } return (bool)_checkAccess.Invoke(chest, new object[1] { player.GetPlayerID() }); } private static int CountItem(string name) { int num = 0; foreach (Container item in UsableChests()) { num += item.GetInventory().CountItems(name, -1, true); } return num; } private static List<ItemData> ChestTrophies() { List<ItemData> list = new List<ItemData>(); if (!_trophies.Value) { return list; } foreach (Container item in UsableChests()) { list.AddRange(from i in item.GetInventory().GetAllItems() where i != null && (int)(i.m_shared?.m_itemType).GetValueOrDefault() == 13 select i); } return list; } private static int RemoveExactItem(ItemData item, int amount) { if (item == null || amount <= 0) { return 0; } foreach (Container item2 in UsableChests()) { Inventory inventory = item2.GetInventory(); if (inventory.ContainsItem(item)) { int stack = item.m_stack; inventory.RemoveItem(item, Mathf.Min(amount, stack)); return stack - (inventory.ContainsItem(item) ? item.m_stack : 0); } } return 0; } private static int RemoveItem(string name, int amount) { int num = 0; foreach (Container item in UsableChests()) { if (num >= amount) { break; } Inventory inventory = item.GetInventory(); int num2 = inventory.CountItems(name, -1, true); if (num2 > 0) { inventory.RemoveItem(name, Mathf.Min(num2, amount - num), -1, true); num += num2 - inventory.CountItems(name, -1, true); } } return num; } } }