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 EpicLoot Craft From Chests v1.2.0
EpicLootCraftFromChests.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace EpicLootCraftFromChests; [BepInPlugin("skiter.epicloot.craftfromchests", "EpicLoot Craft From Chests", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "skiter.epicloot.craftfromchests"; public const string PluginName = "EpicLoot Craft From Chests"; public const string PluginVersion = "1.2.0"; private const string EpicLootGuid = "randyknapp.mods.epicloot"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> Range; internal static ConfigEntry<bool> RespectWards; internal static ConfigEntry<bool> SkipChestsInUse; internal static ConfigEntry<bool> OnlyChestsIOwn; internal static ConfigEntry<bool> DebugLog; internal static readonly List<Container> KnownContainers = new List<Container>(); private static FieldInfo _fNview; private static FieldInfo _fPiece; private static MethodInfo _mCheckAccess; private static MethodInfo _mTableIsVisible; private static PropertyInfo _pTableInstance; private static PropertyInfo _pTableSource; private Harmony _harmony; private void Awake() { //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "[Synced with Server] Let the Epic Loot enchanting table use materials from nearby chests."); Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 20f, "[Synced with Server] How far from the enchanting table (in meters) chests are searched."); RespectWards = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Respect wards", true, "[Synced with Server] Skip chests inside a ward you do not have access to."); SkipChestsInUse = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Skip chests in use", true, "[Synced with Server] Skip chests that someone currently has open."); OnlyChestsIOwn = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "Only chests I already own", false, "[Synced with Server] Safer but less convenient: only use chests whose network ownership already belongs to you (normally the ones nearest to you when nobody else is around). When off, the mod takes ownership of a chest right before taking items from it, the same way opening a chest does."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug log", false, "Write every count and removal to the BepInEx log."); _fNview = AccessTools.Field(typeof(Container), "m_nview"); _fPiece = AccessTools.Field(typeof(Container), "m_piece"); _mCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); if (_fNview == null || _fPiece == null || _mCheckAccess == null) { Log.LogError((object)"Could not find Container internals (Valheim update?). The mod stays disabled."); return; } Type type = AccessTools.TypeByName("EpicLoot.API"); Type type2 = ((!(type == null)) ? type.Assembly.GetType("EpicLoot_UnityLib.EnchantingTableUI") : null); if (type2 == null) { type2 = AccessTools.TypeByName("EpicLoot_UnityLib.EnchantingTableUI"); } if (type2 != null) { _mTableIsVisible = AccessTools.Method(type2, "IsVisible", (Type[])null, (Type[])null); _pTableInstance = AccessTools.Property(type2, "instance"); _pTableSource = AccessTools.Property(type2, "SourceTable"); } if (_mTableIsVisible == null) { Log.LogError((object)"Could not find Epic Loot's EnchantingTableUI. The mod stays disabled."); return; } _harmony = new Harmony("skiter.epicloot.craftfromchests"); _harmony.PatchAll(typeof(ContainerPatches)); _harmony.PatchAll(typeof(ServerSync)); ServerSync.Init(this); RegisterWithEpicLoot(); } private void Update() { ServerSync.Update(); } private void OnDestroy() { ServerSync.Shutdown(); try { Type type = AccessTools.TypeByName("EpicLoot.API"); MethodInfo methodInfo = ((!(type == null)) ? AccessTools.Method(type, "UnregisterInventoryProvider", (Type[])null, (Type[])null) : null); if (methodInfo != null) { methodInfo.Invoke(null, new object[1] { "skiter.epicloot.craftfromchests" }); } } catch (Exception) { } if (_harmony != null) { _harmony.UnpatchSelf(); } } private static void RegisterWithEpicLoot() { Type type = AccessTools.TypeByName("EpicLoot.API"); MethodInfo methodInfo = ((!(type == null)) ? AccessTools.Method(type, "RegisterInventoryProvider", (Type[])null, (Type[])null) : null); if (methodInfo == null) { Log.LogError((object)"This Epic Loot version has no RegisterInventoryProvider (needs 0.14.10 or newer). The mod stays disabled."); return; } object[] parameters = new object[5] { "skiter.epicloot.craftfromchests", null, new Func<string, int>(CountItem), new Func<string, int, int>(RemoveItem), null }; object obj = methodInfo.Invoke(null, parameters); if (obj is bool && (bool)obj) { Log.LogInfo((object)"Registered with Epic Loot: the enchanting table can now use nearby chests."); } else { Log.LogError((object)"Epic Loot refused the registration (already registered?)."); } } private static int CountItem(string itemName) { if (string.IsNullOrEmpty(itemName)) { return 0; } int num = 0; foreach (Container usableContainer in GetUsableContainers()) { Inventory inventory = usableContainer.GetInventory(); if (inventory != null) { num += inventory.CountItems(itemName, -1, true); } } if (DebugLog.Value) { Log.LogInfo((object)("Count " + itemName + " in chests: " + num)); } return num; } private static int RemoveItem(string itemName, int amount) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if (string.IsNullOrEmpty(itemName) || amount <= 0) { return 0; } int num = amount; foreach (Container usableContainer in GetUsableContainers()) { if (num <= 0) { break; } Inventory inventory = usableContainer.GetInventory(); if (inventory == null) { continue; } int num2 = inventory.CountItems(itemName, -1, true); if (num2 <= 0) { continue; } ZNetView val = (ZNetView)_fNview.GetValue(usableContainer); if (!val.IsOwner()) { val.ClaimOwnership(); if (!val.IsOwner()) { continue; } } int num3 = Math.Min(num2, num); inventory.RemoveItem(itemName, num3, -1, true); int num4 = num2 - inventory.CountItems(itemName, -1, true); num -= num4; if (DebugLog.Value) { Log.LogInfo((object)("Took " + num4 + "x " + itemName + " from " + usableContainer.m_name)); } } return amount - num; } private static List<Container> GetUsableContainers() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0097: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); Player localPlayer = Player.m_localPlayer; if (!ServerSync.Enabled || !Object.op_Implicit((Object)(object)localPlayer) || !IsTableOpen()) { return list; } Vector3 tablePosition = GetTablePosition(localPlayer); float range = ServerSync.Range; long playerID = localPlayer.GetPlayerID(); KnownContainers.RemoveAll((Container c) => !Object.op_Implicit((Object)(object)c)); List<KeyValuePair<float, Container>> list2 = new List<KeyValuePair<float, Container>>(); foreach (Container knownContainer in KnownContainers) { try { float num = Vector3.Distance(((Component)knownContainer).transform.position, tablePosition); if (num <= range && IsUsable(knownContainer, playerID)) { list2.Add(new KeyValuePair<float, Container>(num, knownContainer)); } } catch (Exception ex) { if (DebugLog.Value) { Log.LogWarning((object)("Skipped a chest: " + ex.Message)); } } } list2.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key)); foreach (KeyValuePair<float, Container> item in list2) { list.Add(item.Value); } return list; } private static bool IsUsable(Container container, long playerId) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) ZNetView val = (ZNetView)_fNview.GetValue(container); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid()) { return false; } if (Object.op_Implicit((Object)(object)container.m_wagon) || Object.op_Implicit((Object)(object)container.m_rootObjectOverride)) { return false; } Piece val2 = (Piece)_fPiece.GetValue(container); if (!Object.op_Implicit((Object)(object)val2) || !val2.IsPlacedByPlayer()) { return false; } if (ServerSync.SkipChestsInUse && (container.IsInUse() || val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1)) { return false; } if (ServerSync.OnlyChestsIOwn && !val.IsOwner()) { return false; } if (!(bool)_mCheckAccess.Invoke(container, new object[1] { playerId })) { return false; } if (ServerSync.RespectWards && container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { return false; } return true; } private static bool IsTableOpen() { try { return (bool)_mTableIsVisible.Invoke(null, null); } catch (Exception) { return false; } } private static Vector3 GetTablePosition(Player player) { //IL_007e: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) try { object obj = ((!(_pTableInstance == null)) ? _pTableInstance.GetValue(null, null) : null); Component val = (Component)((obj != null && !(_pTableSource == null)) ? /*isinst with value type is only supported in some contexts*/: null); if (Object.op_Implicit((Object)(object)val)) { return val.transform.position; } } catch (Exception) { } return ((Component)player).transform.position; } } [HarmonyPatch] internal static class ContainerPatches { private static int _addsSincePrune; [HarmonyPatch(typeof(Container), "Awake")] [HarmonyPostfix] private static void AwakePostfix(Container __instance) { ZNet instance = ZNet.instance; if (Object.op_Implicit((Object)(object)instance) && instance.IsDedicated()) { return; } if (++_addsSincePrune >= 256) { _addsSincePrune = 0; Plugin.KnownContainers.RemoveAll((Container c) => !Object.op_Implicit((Object)(object)c)); } if (Object.op_Implicit((Object)(object)__instance) && !Plugin.KnownContainers.Contains(__instance)) { Plugin.KnownContainers.Add(__instance); } } } [HarmonyPatch] internal static class ServerSync { private const string RpcName = "skiter.epicloot.craftfromchests.config"; private const int ProtocolVersion = 1; private static Plugin _plugin; private static FileSystemWatcher _watcher; private static volatile bool _fileChanged; private static bool _hasServerValues; private static bool _sEnabled; private static float _sRange; private static bool _sRespectWards; private static bool _sSkipChestsInUse; private static bool _sOnlyChestsIOwn; internal static bool Enabled => (!_hasServerValues) ? Plugin.Enabled.Value : _sEnabled; internal static float Range => (!_hasServerValues) ? Plugin.Range.Value : _sRange; internal static bool RespectWards => (!_hasServerValues) ? Plugin.RespectWards.Value : _sRespectWards; internal static bool SkipChestsInUse => (!_hasServerValues) ? Plugin.SkipChestsInUse.Value : _sSkipChestsInUse; internal static bool OnlyChestsIOwn => (!_hasServerValues) ? Plugin.OnlyChestsIOwn.Value : _sOnlyChestsIOwn; internal static void Init(Plugin plugin) { _plugin = plugin; ((BaseUnityPlugin)plugin).Config.SettingChanged += delegate { BroadcastIfServer(); }; try { string configFilePath = ((BaseUnityPlugin)plugin).Config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)); _watcher.Changed += delegate { _fileChanged = true; }; _watcher.Created += delegate { _fileChanged = true; }; _watcher.Renamed += delegate { _fileChanged = true; }; _watcher.IncludeSubdirectories = false; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Config file watcher unavailable (" + ex.Message + "); edits to the .cfg will apply after a restart.")); } } internal static void Update() { if (_fileChanged) { _fileChanged = false; try { ((BaseUnityPlugin)_plugin).Config.Reload(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not reload the config: " + ex.Message)); return; } BroadcastIfServer(); } } internal static void Shutdown() { if (_watcher != null) { _watcher.EnableRaisingEvents = false; _watcher.Dispose(); _watcher = null; } } private static ZPackage BuildPackage() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(Plugin.Enabled.Value); val.Write(Plugin.Range.Value); val.Write(Plugin.RespectWards.Value); val.Write(Plugin.SkipChestsInUse.Value); val.Write(Plugin.OnlyChestsIOwn.Value); return val; } private static void SendTo(ZRpc rpc) { if (rpc != null) { rpc.Invoke("skiter.epicloot.craftfromchests.config", new object[1] { BuildPackage() }); } } private static void BroadcastIfServer() { ZNet instance = ZNet.instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.IsServer()) { return; } foreach (ZNetPeer peer in instance.GetPeers()) { if (peer != null && peer.m_rpc != null && peer.IsReady()) { SendTo(peer.m_rpc); } } } private static void RPC_ReceiveConfig(ZRpc rpc, ZPackage pkg) { ZNet instance = ZNet.instance; if (!Object.op_Implicit((Object)(object)instance) || !instance.IsServer()) { int num = pkg.ReadInt(); if (num != 1) { Plugin.Log.LogWarning((object)("Server runs a different version of this mod (settings format " + num + "); using local settings. Update the mod on both sides.")); return; } _sEnabled = pkg.ReadBool(); _sRange = pkg.ReadSingle(); _sRespectWards = pkg.ReadBool(); _sSkipChestsInUse = pkg.ReadBool(); _sOnlyChestsIOwn = pkg.ReadBool(); _hasServerValues = true; Plugin.Log.LogInfo((object)("Using the server's settings: Enabled=" + _sEnabled + ", Range=" + _sRange + ", Respect wards=" + _sRespectWards + ", Skip chests in use=" + _sSkipChestsInUse + ", Only chests I already own=" + _sOnlyChestsIOwn)); } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPostfix] private static void OnNewConnectionPostfix(ZNet __instance, ZNetPeer peer) { if (!__instance.IsServer() && peer != null && peer.m_rpc != null) { peer.m_rpc.Register<ZPackage>("skiter.epicloot.craftfromchests.config", (Action<ZRpc, ZPackage>)RPC_ReceiveConfig); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPostfix] private static void PeerInfoPostfix(ZNet __instance, ZRpc rpc) { if (__instance.IsServer()) { SendTo(rpc); } } [HarmonyPatch(typeof(ZNet), "OnDestroy")] [HarmonyPostfix] private static void ZNetDestroyPostfix() { _hasServerValues = false; } }