using System; using System.Collections; 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 HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("SmartDeposit")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.2.0")] [assembly: AssemblyInformationalVersion("0.1.2")] [assembly: AssemblyProduct("SmartDeposit")] [assembly: AssemblyTitle("SmartDeposit")] [assembly: AssemblyVersion("0.1.2.0")] namespace SmartDeposit; [BepInPlugin("local.valheim.smartdeposit", "Smart Deposit", "0.1.2")] public sealed class Plugin : BaseUnityPlugin { private sealed class Request { public Player Player; public bool Done; public bool Cancelled; public float Deadline; } [HarmonyPatch(typeof(Container), "RPC_StackResponse")] private static class ResponsePatch { private static bool Prefix(Container __instance, bool __1) { if (!Object.op_Implicit((Object)(object)instance) || !instance.pending.TryGetValue(__instance, out var value)) { return true; } instance.pending.Remove(__instance); instance.Response(__instance, __1, value); return false; } } [HarmonyPatch(typeof(Container), "StackAll")] private static class StackPatch { private static bool Prefix(Container __instance) { if (Object.op_Implicit((Object)(object)instance) && instance.pending.ContainsKey(__instance)) { return (Object)(object)instance.dispatching == (Object)(object)__instance; } return true; } } private static class CommandPatch { internal static bool Prefix(Terminal __instance, string __0) { string[] array = (__0 ?? "").Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || !array[0].Equals("smartdeposit", StringComparison.OrdinalIgnoreCase)) { return true; } if (!Object.op_Implicit((Object)(object)instance) || !((Behaviour)instance).enabled) { __instance.AddString("Smart Deposit unavailable."); return false; } if (array.Length == 1) { instance.Begin(); return false; } if (array.Length == 3 && (array[1].Equals("keep", StringComparison.OrdinalIgnoreCase) || array[1].Equals("unkeep", StringComparison.OrdinalIgnoreCase))) { HashSet hashSet = new HashSet(from s in instance.keep.Value.Split(',') select s.Trim() into s where s.Length > 0 select s, StringComparer.OrdinalIgnoreCase); if (array[1].Equals("keep", StringComparison.OrdinalIgnoreCase)) { hashSet.Add(array[2]); } else { hashSet.Remove(array[2]); } instance.keep.Value = string.Join(",", hashSet.OrderBy((string s) => s)); __instance.AddString("Smart Deposit keep list: " + instance.keep.Value); return false; } __instance.AddString("Usage: /smartdeposit; /smartdeposit keep Wood; /smartdeposit unkeep Wood. Keep list: " + instance.keep.Value); return false; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func <>9__20_2; public static ConsoleEvent <>9__25_0; internal bool b__20_2(Container c) { return !Object.op_Implicit((Object)(object)c); } internal void b__25_0(ConsoleEventArgs args) { CommandPatch.Prefix(args.Context, args.FullLine); } } public const string Id = "local.valheim.smartdeposit"; private static Plugin instance; private Harmony harmony; private ConfigEntry key; private ConfigEntry range; private ConfigEntry keep; private bool busy; private Container dispatching; private int moved; private int chests; private readonly Dictionary pending = new Dictionary(); private static readonly MethodInfo Load = AccessTools.Method(typeof(Container), "Load", (Type[])null, (Type[])null); private static readonly MethodInfo CheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null); private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown instance = this; key = ((BaseUnityPlugin)this).Config.Bind("General", "DepositKey", new KeyboardShortcut((KeyCode)291, Array.Empty()), "Deposit matching items into nearby chests."); range = ((BaseUnityPlugin)this).Config.Bind("General", "Range", 10f, new ConfigDescription("Search range in metres.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 20f), Array.Empty())); keep = ((BaseUnityPlugin)this).Config.Bind("General", "KeepItems", "", "Comma-separated item prefab names to protect. Use /smartdeposit keep Wood, or /smartdeposit unkeep Wood."); harmony = new Harmony("local.valheim.smartdeposit"); try { harmony.PatchAll(); RegisterCommand(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Smart Deposit 0.1.2 loaded: F10 or /smartdeposit."); } catch (Exception ex) { harmony.UnpatchSelf(); ((Behaviour)this).enabled = false; ((BaseUnityPlugin)this).Logger.LogError((object)ex); } } private void Update() { //IL_0039: 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) if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !Menu.IsVisible()) { KeyboardShortcut value = key.Value; if (((KeyboardShortcut)(ref value)).IsDown()) { Begin(); } } } private void Say(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Smart Deposit: " + message, 0, (Sprite)null, false); } } private void Begin() { if (busy) { Say("already working."); } else if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || InventoryGui.IsVisible()) { Say("close your inventory first."); } else { ((MonoBehaviour)this).StartCoroutine(Deposit()); } } private bool Allowed(Container c, Player p) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) if (!Object.op_Implicit((Object)(object)c) || !Object.op_Implicit((Object)(object)p) || (Object)(object)p != (Object)(object)Player.m_localPlayer || ((Character)p).IsDead() || InventoryGui.IsVisible()) { return false; } if (Vector3.Distance(((Component)c).transform.position, ((Component)p).transform.position) > range.Value || c.IsInUse()) { return false; } Piece component = ((Component)c).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || component.GetCreator() == 0L || Object.op_Implicit((Object)(object)((Component)c).GetComponentInParent())) { return false; } ZNetView component2 = ((Component)c).GetComponent(); if (Object.op_Implicit((Object)(object)component2) && component2.IsValid() && (bool)CheckAccess.Invoke(c, new object[1] { p.GetPlayerID() })) { return PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false); } return false; } private bool Eligible(ItemData item, Player p) { if (item.m_gridPos.y == 0 || item.m_equipped || ((Humanoid)p).IsItemEquiped(item) || item.m_stack <= 0) { return false; } if (item.m_customData != null && item.m_customData.Count > 0) { return false; } string prefab = (Object.op_Implicit((Object)(object)item.m_dropPrefab) ? ((Object)item.m_dropPrefab).name : ""); return !keep.Value.Split(',').Any((string x) => x.Trim().Equals(prefab, StringComparison.OrdinalIgnoreCase)); } private IEnumerator Deposit() { busy = true; moved = 0; chests = 0; Player p = Player.m_localPlayer; try { Container[] array = pending.Keys.Where((Container val2) => !Object.op_Implicit((Object)(object)val2)).ToArray(); foreach (Container val in array) { pending.Remove(val); } Container[] array2 = (from val2 in Object.FindObjectsByType((FindObjectsSortMode)0) where Allowed(val2, p) orderby Vector3.Distance(((Component)val2).transform.position, ((Component)p).transform.position) select val2).ToArray(); Container[] array3 = array2; foreach (Container c in array3) { if (!Allowed(c, p) || pending.ContainsKey(c)) { continue; } Request request = new Request { Player = p, Deadline = Time.realtimeSinceStartup + 4f }; pending.Add(c, request); try { dispatching = c; c.StackAll(); } catch (Exception ex) { request.Cancelled = true; request.Done = true; ((BaseUnityPlugin)this).Logger.LogWarning((object)ex); } finally { dispatching = null; } while (!request.Done && Object.op_Implicit((Object)(object)c) && Time.realtimeSinceStartup < request.Deadline) { yield return null; } if (!request.Done) { request.Cancelled = true; } yield return null; } Say((moved > 0) ? $"deposited {moved} items into {chests} chests." : "nothing deposited. No accessible matching space, or all items protected."); } finally { busy = false; } } private void Response(Container c, bool granted, Request request) { try { if (!granted || request.Cancelled || Time.realtimeSinceStartup > request.Deadline || !Allowed(c, request.Player)) { return; } ZNetView component = ((Component)c).GetComponent(); if (!component.IsOwner()) { return; } Load.Invoke(c, null); if (Allowed(c, request.Player) && component.IsOwner()) { Inventory inventory = ((Humanoid)request.Player).GetInventory(); Inventory inventory2 = c.GetInventory(); int num = Transfer(inventory, inventory2, (ItemData item) => Eligible(item, request.Player)); moved += num; if (num > 0) { chests++; } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); Say("transfer stopped; check the BepInEx log."); } finally { request.Done = true; } } internal static int Transfer(Inventory source, Inventory target, Func eligible) { int num = 0; ItemData[] array = source.GetAllItems().ToArray(); foreach (ItemData item in array) { if (!eligible(item) || !target.GetAllItems().Any((ItemData t) => t.IsSameType(item))) { continue; } ItemData[] array2 = (from t in target.GetAllItems() where t.IsSameType(item) select t).ToArray(); foreach (ItemData val in array2) { int num3 = Math.Min(item.m_stack, Math.Max(0, val.m_shared.m_maxStackSize - val.m_stack)); if (num3 > 0) { int stack = item.m_stack; target.MoveItemToThis(source, item, num3, val.m_gridPos.x, val.m_gridPos.y); num += stack - item.m_stack; } } for (int num4 = 0; num4 < target.GetHeight(); num4++) { if (item.m_stack <= 0) { break; } for (int num5 = 0; num5 < target.GetWidth(); num5++) { if (item.m_stack <= 0) { break; } if (target.GetItemAt(num5, num4) == null) { int stack2 = item.m_stack; target.MoveItemToThis(source, item, Math.Min(item.m_stack, item.m_shared.m_maxStackSize), num5, num4); num += stack2 - item.m_stack; } } } } return num; } private static void RegisterCommand() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown object obj = <>c.<>9__25_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { CommandPatch.Prefix(args.Context, args.FullLine); }; <>c.<>9__25_0 = val; obj = (object)val; } new ConsoleCommand("smartdeposit", "Deposit nearby matching items. Usage: smartdeposit [keep|unkeep ItemPrefab]", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } instance = null; } }