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 ItemPull v0.4.1
ItemPull.dll
Decompiled 2 days 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.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; 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: InternalsVisibleTo("ItemPull.UnitySmoke")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ItemPull")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.4.1.0")] [assembly: AssemblyInformationalVersion("0.4.1")] [assembly: AssemblyProduct("ItemPull")] [assembly: AssemblyTitle("ItemPull")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ItemPull { internal sealed class ChestLocator { private readonly ItemPullPlugin plugin; private SearchResult? result; private float expires; private Player? owner; private GUIStyle? labelStyle; internal ChestLocator(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Show(SearchResult result) { this.result = result; owner = Player.m_localPlayer; expires = Time.unscaledTime + plugin.LocateSeconds.Value; } internal void Clear() { result = null; owner = null; } internal void Tick() { if (result != null && (!Object.op_Implicit((Object)(object)owner) || (Object)(object)owner != (Object)(object)Player.m_localPlayer || ((Character)owner).IsDead() || Time.unscaledTime >= expires)) { Clear(); } } internal void Draw() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_004a: 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_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_02f2: 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_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_012f: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (result == null || !Object.op_Implicit((Object)(object)owner) || (int)Event.current.type != 7) { return; } Camera main = Camera.main; if (!Object.op_Implicit((Object)(object)main)) { return; } if (labelStyle == null) { labelStyle = new GUIStyle(GUI.skin.box) { alignment = (TextAnchor)4, fontSize = 16, wordWrap = false }; } Color color = GUI.color; foreach (Container chest in result.Chests) { if (!plugin.Search.CanAccess(chest, owner)) { continue; } int num = chest.GetInventory().GetAllItems().Where(result.Key.Matches) .Sum((ItemData i) => i.m_stack); if (num > 0) { Bounds bounds = BoundsFor(chest); Vector3 val = main.WorldToScreenPoint(((Bounds)(ref bounds)).center + Vector3.up * (((Bounds)(ref bounds)).extents.y + 0.2f)); float num2 = Vector3.Distance(((Component)owner).transform.position, ((Component)chest).transform.position); bool flag = val.z > 0f && val.x > 140f && val.x < (float)(Screen.width - 140) && val.y > 35f && val.y < (float)(Screen.height - 35); if (flag) { DrawBounds(main, bounds); } else if (val.z <= 0f) { val.x = (float)Screen.width - val.x; val.y = (float)Screen.height - val.y; } float num3 = Mathf.Clamp(val.x, 140f, (float)(Screen.width - 140)); float num4 = Mathf.Clamp((float)Screen.height - val.y, 35f, (float)(Screen.height - 35)); GUI.color = new Color(0.35f, 1f, 0.9f, 1f); string text = Localization.instance.Localize(chest.m_name); GUI.Box(new Rect(num3 - 140f, num4 - 26f, 280f, 48f), string.Format("{0}{1} · {2:0.#}m\n{3} × {4}", flag ? "" : "➤ ", text, num2, result.Name, num), labelStyle); } } GUI.color = color; } internal static Bounds BoundsFor(Container chest) { //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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_0083: 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_007a: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)chest).transform.position + Vector3.up * 0.4f, Vector3.one * 0.8f); bool flag = true; Renderer[] componentsInChildren = ((Component)chest).GetComponentsInChildren<Renderer>(); foreach (Renderer val in componentsInChildren) { if ((val is MeshRenderer || val is SkinnedMeshRenderer) && val.enabled && ((Component)val).gameObject.activeInHierarchy) { if (flag) { bounds = val.bounds; flag = false; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } ((Bounds)(ref bounds)).Expand(0.06f); return bounds; } private static void DrawBounds(Camera camera, Bounds bounds) { //IL_0002: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0024: Unknown result type (might be due to invalid IL or missing references) //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_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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007e: 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) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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) //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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0146: 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_0150: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0177: 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_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) Vector3 min = ((Bounds)(ref bounds)).min; Vector3 max = ((Bounds)(ref bounds)).max; Vector3[] array = (Vector3[])(object)new Vector3[8] { new Vector3(min.x, min.y, min.z), new Vector3(max.x, min.y, min.z), new Vector3(max.x, min.y, max.z), new Vector3(min.x, min.y, max.z), new Vector3(min.x, max.y, min.z), new Vector3(max.x, max.y, min.z), new Vector3(max.x, max.y, max.z), new Vector3(min.x, max.y, max.z) }; int[] array2 = new int[24] { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 }; GUI.color = new Color(0.2f, 1f, 0.85f, 0.9f); Vector2 val3 = default(Vector2); Vector2 val4 = default(Vector2); for (int i = 0; i < array2.Length; i += 2) { Vector3 val = camera.WorldToScreenPoint(array[array2[i]]); Vector3 val2 = camera.WorldToScreenPoint(array[array2[i + 1]]); if (!(val.z <= 0f) && !(val2.z <= 0f)) { ((Vector2)(ref val3))..ctor(val.x, (float)Screen.height - val.y); ((Vector2)(ref val4))..ctor(val2.x, (float)Screen.height - val2.y); Matrix4x4 matrix = GUI.matrix; GUIUtility.RotateAroundPivot(Mathf.Atan2(val4.y - val3.y, val4.x - val3.x) * 57.29578f, val3); float x = val3.x; float y = val3.y; Vector2 val5 = val4 - val3; GUI.DrawTexture(new Rect(x, y, ((Vector2)(ref val5)).magnitude, 2f), (Texture)(object)Texture2D.whiteTexture); GUI.matrix = matrix; } } } } internal readonly struct ItemKey : IEquatable<ItemKey> { internal readonly string Name; internal readonly int Quality; internal readonly int Variant; internal readonly int WorldLevel; internal ItemKey(ItemData item) { Name = item.m_shared.m_name; Quality = item.m_quality; Variant = item.m_variant; WorldLevel = item.m_worldLevel; } public bool Equals(ItemKey other) { if (Name == other.Name && Quality == other.Quality && Variant == other.Variant) { return WorldLevel == other.WorldLevel; } return false; } public override bool Equals(object? obj) { if (obj is ItemKey other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(Name, Quality, Variant, WorldLevel); } internal bool Matches(ItemData item) { return Equals(new ItemKey(item)); } } internal sealed class SearchResult { internal ItemKey Key; internal string Name = ""; internal Sprite? Icon; internal int Total; internal readonly List<Container> Chests = new List<Container>(); } internal sealed class ChestSearch { private readonly ItemPullPlugin plugin; private readonly HashSet<Container> chests = new HashSet<Container>(); internal ChestSearch(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Register(Container chest) { chests.Add(chest); } internal List<Container> Accessible(Player player) { chests.RemoveWhere((Container chest) => !Object.op_Implicit((Object)(object)chest)); return chests.Where((Container chest) => CanAccess(chest, player)).OrderBy(delegate(Container chest) { //IL_0006: 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) //IL_001b: 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) Vector3 val = ((Component)chest).transform.position - ((Component)player).transform.position; return ((Vector3)(ref val)).sqrMagnitude; }).ToList(); } internal bool CanAccess(Container chest, Player player) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0088: 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_00bc: Invalid comparison between Unknown and I4 //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)chest) || !Object.op_Implicit((Object)(object)player) || !((Behaviour)chest).isActiveAndEnabled || !Object.op_Implicit((Object)(object)chest.m_nview) || !chest.m_nview.IsValid() || chest.GetInventory() == null) { return false; } if (chest.m_autoDestroyEmpty || Object.op_Implicit((Object)(object)((Component)chest).GetComponentInParent<TombStone>()) || Object.op_Implicit((Object)(object)chest.m_wagon) || Object.op_Implicit((Object)(object)chest.m_rootObjectOverride)) { return false; } Vector3 val = ((Component)chest).transform.position - ((Component)player).transform.position; if (((Vector3)(ref val)).sqrMagnitude > plugin.Radius.Value * plugin.Radius.Value) { return false; } if ((int)chest.m_privacy != 2 && !Object.op_Implicit((Object)(object)chest.m_piece)) { return false; } if (chest.CheckAccess(player.GetPlayerID())) { if (chest.m_checkGuardStone) { return PrivateArea.CheckAccess(((Component)chest).transform.position, 0f, false, false); } return true; } return false; } internal List<SearchResult> Find(string query) { Player player = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)player)) { return new List<SearchResult>(); } chests.RemoveWhere((Container chest) => !Object.op_Implicit((Object)(object)chest)); Dictionary<ItemKey, SearchResult> dictionary = new Dictionary<ItemKey, SearchResult>(); query = query.Trim(); foreach (Container chest in chests) { if (!CanAccess(chest, player)) { continue; } chest.Load(); foreach (ItemData allItem in chest.GetInventory().GetAllItems()) { string text = Localization.instance.Localize(allItem.m_shared.m_name); if (text.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0) { ItemKey key = new ItemKey(allItem); if (!dictionary.TryGetValue(key, out var value)) { value = new SearchResult { Key = key, Name = text, Icon = allItem.GetIcon() }; dictionary.Add(key, value); } value.Total += allItem.m_stack; if (!value.Chests.Contains(chest)) { value.Chests.Add(chest); } } } } foreach (SearchResult value2 in dictionary.Values) { value2.Chests.Sort(delegate(Container a, Container b) { //IL_0006: 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) //IL_001b: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_004b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)a).transform.position - ((Component)player).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - ((Component)player).transform.position; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); }); } return dictionary.Values.OrderBy<SearchResult, string>((SearchResult r) => r.Name, StringComparer.OrdinalIgnoreCase).ThenBy((SearchResult r) => r.Key.Quality).ThenBy((SearchResult r) => r.Key.Variant) .ToList(); } } internal sealed class DepositGroups { internal sealed class Group { internal readonly string Id; internal readonly ConfigEntry<string> Name; internal readonly ConfigEntry<string> Items; internal Group(ConfigFile config, string section, string name, string items) { Id = section; Name = config.Bind<string>(section, "Name", name, "Editable group name. A blank name disables this group."); Items = config.Bind<string>(section, "Items", items, "Comma-separated prefab IDs (not translated names). Supports * wildcards and type:ItemType selectors. Blank disables the group. Custom groups take priority, then numbered active groups; first match wins."); } } internal readonly ConfigEntry<bool> Enabled; internal readonly ConfigEntry<bool> UseBiomeGroups; internal readonly ConfigEntry<bool> ApplyToMiddleClick; internal readonly List<Group> Standard = new List<Group>(); internal readonly List<Group> Biomes = new List<Group>(); internal readonly List<Group> Custom = new List<Group>(); private readonly ItemPullPlugin plugin; private bool dirty = true; private readonly List<(string Id, Func<ItemData, bool>[] Rules)> rules = new List<(string, Func<ItemData, bool>[])>(); private readonly Dictionary<(string Prefab, string Name, ItemType Type), string?> itemGroups = new Dictionary<(string, string, ItemType), string>(); internal static readonly (string Name, string Items)[] StandardDefaults = new(string, string)[20] { ("Wood", "Wood, FineWood, RoundLog, ElderBark, YggdrasilWood, Blackwood, Frostwood"), ("Stone and Minerals", "Stone, Flint, Obsidian, Crystal, BlackMarble, Grausten, SulfurStone, Ice, StoneRock"), ("Ore and Scrap", "CopperOre, CopperScrap, TinOre, IronOre, IronScrap, BronzeScrap, SilverOre, BlackMetalScrap, FlametalOre, FlametalOreNew, GoldOre"), ("Metal Bars", "Copper, Tin, Bronze, Iron, Silver, BlackMetal, Flametal, FlametalNew, Gold"), ("Hides and Leather", "LeatherScraps, DeerHide, TrollHide, WolfPelt, LoxPelt, ScaleHide, AskHide, BjornHide, MooseHide, SealHide, Leatherstraps"), ("Creature Materials", "BoneFragments, Feathers, Entrails, Bloodbag, Chitin, GreydwarfEye, WolfFang, WolfClaw, FreezeGland, Ooze, OozeMork, Needle, Root, Carapace, Bilebag, Mandible, CharredBone, AskBladder, MorgenHeart, MorgenSinew, BonemawSerpentScale, BonemawSerpentTooth, SerpentScale, BjornPaw, MoleClaws, MooseSinew, ElakingHairBundle, WolfHairBundle, GiantBloodSack, HatefulBlood"), ("Seeds and Planting", "*Seeds, FirCone, FirConeFrost, PineCone, Acorn, AncientSeed, QueenBee, AsksvinEgg"), ("Cooking Ingredients", "RawMeat, DeerMeat, NeckTail, FishRaw, FishAnglerRaw, type:Fish, WolfMeat, LoxMeat, SerpentMeat, HareMeat, ChickenMeat, ChickenEgg, BugMeat, AsksvinMeat, VoltureMeat, VoltureEgg, BoneMawSerpentMeat, BjornMeat, MooseMeat, SealBlubber, RottenMeat, Larva, Raspberry, Blueberries, Cloudberry, Lingonberry, Vineberry, Carrot, Turnip, Onion, Poteitr, Kale, Oat, OatFlour, Barley, BarleyFlour, Honey, Dandelion, Thistle, Mushroom, MushroomBlue, MushroomYellow, MushroomBzerker, MushroomSmokePuff, MushroomJotunPuffs, MushroomMagecap, RoyalJelly, Sap, Fiddleheadfern, FreshSeaweed, Spice*, BreadDough, LoxPieUncooked, FishAndBreadUncooked, HoneyGlazedChickenUncooked, MagicallyStuffedShroomUncooked, MeatPlatterUncooked, MisthareSupremeUncooked, BakedPoteitrUncooked, KaleChipsUncooked, OvenPancakeUncooked, PiquantPieUncooked, RoastedCrustPieUncooked, VikingCupcakeUncooked"), ("Mead Bases", "MeadBase*, BarleyWineBase"), ("Mead and Potions", "Mead*, BarleyWine, Pukeberries"), ("Prepared Food", "type:Consumable, Feast*_Material"), ("Textiles and Fibres", "Flax, LinenThread, JuteRed, JuteBlue, NornThread, CuredSquirrelHamstring, CandleWick"), ("Fuel and Resin", "Coal, Resin, Tar, CharcoalResin, FrozenFuel, MemorialCoal"), ("Valuables", "Coins, Amber, AmberPearl, Ruby, SilverNecklace, AncientCoin, AncientGemstone*"), ("Trophies", "type:Trophy, Trophy*"), ("Tools and Utility", "type:Tool, type:Utility, type:Trinket, type:Torch, Pickaxe*, FishingRod, KnifeButcher, Saddle*, Tankard*, Lantern*, GrapplingHook, BarberKit"), ("Weapons and Shields", "type:OneHandedWeapon, type:TwoHandedWeapon, type:TwoHandedWeaponLeft, type:Bow, type:Shield"), ("Ammunition", "type:Ammo, type:AmmoNonEquipable, Arrow*, Bolt*, Bomb*, TurretBolt*, FishingBait*"), ("Armour and Clothing", "type:Helmet, type:Chest, type:Legs, type:Hands, type:Shoulder"), ("Special Materials", "SurtlingCore, BlackCore, MoltenCore, FrostCore, ShieldCore, Eitr, Softtissue, Wisp, Guck, YmirRemains, Thunderstone, HardAntler, DragonTear, DragonEgg, WitheredBone, GoblinTotem, YagluthDrop, QueenDrop, FaderDrop, FrozenKingDrop, FaderEmber, Gemstone*, DvergrNeedle, DvergrKey*, CryptKey, Chain, BronzeNails, IronNails, MechanicalSpring, SharpeningStone, Ectoplasm, Voidplasm, CelestialFeather, WrithanRoots, CrownJewel, BloodGoldKey, Dyrnwyn*Fragment, HildirKey*, Bell*, Mold*, Orb*, PowderedDragonEgg") }; internal static readonly (string Name, string Items)[] BiomeDefaults = new(string, string)[9] { ("Meadows", "Wood, FineWood, Stone, Flint, Resin, Coal, LeatherScraps, DeerHide, RawMeat, DeerMeat, NeckTail, Raspberry, Mushroom, Honey, Dandelion, QueenBee, BeechSeeds, BirchSeeds, Acorn, HardAntler, TrophyBoar, TrophyDeer, TrophyNeck, TrophyEikthyr, ArmorRags*, ArmorLeather*, HelmetLeather, CapeDeerHide, ArrowWood, ArrowFlint, ArrowFire, AxeStone, AxeFlint, KnifeFlint, SpearFlint, Club, Bow, ShieldWood*, Hammer, Hoe, CookedMeat, CookedDeerMeat, NeckTailGrilled, BoarJerky, DeerStew, MinceMeatSauce, MeadBaseHealthMinor, MeadHealthMinor, FeastMeadows_Material"), ("Black Forest", "RoundLog, CopperOre, CopperScrap, Copper, TinOre, Tin, Bronze, BronzeScrap, BronzeNails, TrollHide, BoneFragments, GreydwarfEye, Blueberries, Carrot, CarrotSeeds, MushroomYellow, Thistle, FirCone, PineCone, AncientSeed, SurtlingCore, TrophyGreydwarf*, TrophyForestTroll, TrophySkeleton, TrophySkeletonHildir, TrophyGhost, TrophyTheElder, CryptKey, ArmorBronze*, ArmorTrollLeather*, HelmetBronze, HelmetTrollLeather, CapeTrollHide, AtgeirBronze, AxeBronze, MaceBronze, SwordBronze, SpearBronze, PickaxeBronze, KnifeCopper, ShieldBronzeBuckler, BowFineWood, Cultivator, CarrotSoup, QueensJam, DeerStew, SpiceForests, FeastBlackforest_Material"), ("Swamp", "ElderBark, IronOre, IronScrap, Iron, IronNails, Entrails, Bloodbag, Ooze, Root, Chain, Guck, Turnip, TurnipSeeds, WitheredBone, TrophyAbomination, TrophyBlob, TrophyDraugr*, TrophyLeech, TrophySkeletonPoison, TrophySurtling, TrophyWraith, TrophyBonemass, Wishbone, ArmorIron*, ArmorRoot*, HelmetIron, HelmetRoot, AtgeirIron, AxeIron, Battleaxe, MaceIron, SwordIron, PickaxeIron, ShieldIron*, ShieldBanded, BowHuntsman, SledgeIron, ArrowIron, ArrowPoison, BombOoze, Sausages, BlackSoup, TurnipStew, MeadBasePoisonResist, MeadPoisonResist, FeastSwamps_Material"), ("Mountains", "SilverOre, Silver, Obsidian, Crystal, WolfPelt, WolfFang, WolfClaw, WolfHairBundle, WolfMeat, FreezeGland, Onion, OnionSeeds, DragonEgg, DragonTear, JuteRed, TrophyWolf, TrophyHatchling, TrophyFenring, TrophyCultist*, TrophyUlv, TrophySGolem, TrophyDragonQueen, ArmorWolf*, ArmorFenring*, HelmetDrake, HelmetFenring, CapeWolf, BowDraugrFang, BattleaxeCrystal, SwordSilver, MaceSilver, KnifeSilver, ShieldSilver, SpearWolfFang, FistFenrirClaw, ArrowSilver, ArrowObsidian, ArrowFrost, WolfJerky, WolfMeatSkewer, OnionSoup, Eyescream, MeadBaseFrostResist, MeadFrostResist, SpiceMountains, FeastMountains_Material"), ("Plains", "BlackMetalScrap, BlackMetal, LoxPelt, LoxMeat, Needle, Tar, Flax, LinenThread, Barley, BarleyFlour, Cloudberry, GoblinTotem, YagluthDrop, TrophyDeathsquito, TrophyLox, TrophyGoblin*, TrophyGrowth, ArmorPadded*, ArmorLox*, HelmetPadded, HelmetLox, CapeLinen, CapeLox, AtgeirBlackmetal, AxeBlackMetal, KnifeBlackMetal, SwordBlackmetal, MaceNeedle, ShieldBlackmetal*, ArrowNeedle, BarleyWine, BarleyWineBase, Bread, BreadDough, LoxPie, LoxPieUncooked, BloodPudding, FishWraps, SaddleLox, SpicePlains, FeastPlains_Material"), ("Mistlands", "YggdrasilWood, BlackMarble, BlackCore, Eitr, Softtissue, Wisp, Sap, Carapace, Bilebag, Mandible, ScaleHide, HareMeat, BugMeat, RoyalJelly, MushroomJotunPuffs, MushroomMagecap, DvergrNeedle, DvergrKey*, JuteBlue, QueenDrop, TrophySeeker*, TrophyGjall, TrophyTick, TrophyHare, TrophyDvergr, ArmorCarapace*, ArmorMageChest, ArmorMageLegs, HelmetCarapace, HelmetMage, CapeFeather, Demister, PickaxeBlackMetal, BowSpineSnap, CrossbowArbalest, StaffFireball, StaffIceShards, StaffShield, StaffSkeleton, AtgeirHimminAfl, THSwordKrom, KnifeSkollAndHati, SwordMistwalker, ShieldCarapace*, SpearCarapace, SledgeDemolisher, ArrowCarapace, BoltBone, BoltIron, BoltBlackmetal, BoltCarapace, BombBile, FishAndBread*, MisthareSupreme*, SeekerAspic, Salad, MushroomOmelette, YggdrasilPorridge, MeadEitr*, MeadBaseEitr*, SpiceMistlands, FeastMistlands_Material"), ("Ashlands", "Blackwood, Grausten, SulfurStone, Flametal*, AskHide, AskBladder, AsksvinMeat, AsksvinEgg, VoltureMeat, VoltureEgg, CharredBone, Charredskull, CharredCogwheel, MorgenHeart, MorgenSinew, BonemawSerpentScale, BonemawSerpentTooth, BoneMawSerpentMeat, Fiddleheadfern, Vineberry, MoltenCore, ShieldCore, Gemstone*, FaderDrop, FaderEmber, Dyrnwyn*Fragment, TrophyAsksvin, TrophyCharred*, TrophyVolture, TrophyMorgen, TrophyBonemawSerpent, TrophyFallenValkyrie, TrophyFader, ArmorFlametal*, ArmorAshlands*, ArmorMage*_Ashlands, HelmetFlametal, HelmetAshlandsMediumHood, HelmetMage_Ashlands, CapeAsh, CapeAsksvin, SaddleAsksvin, AxeBerzerkr*, SwordNiedhogg*, THSwordSlayer*, MaceEldner*, SpearSplitner*, BowAshlands*, CrossbowRipper*, StaffClusterbomb, StaffGreenRoots, StaffLightning, StaffRedTroll, ShieldFlametal*, ArrowCharred, BoltCharred, BombLava, BombSiege, PiquantPie*, RoastedCrustPie*, ScorchingMedley, SizzlingBerryBroth, SparklingShroomshake, MashedMeat, FierySvinstew, SpiceAshlands, FeastAshlands_Material"), ("Deep North", "Frostwood, Ice, FrostCore, FrozenFuel, Gold, GoldOre, BjornHide, BjornPaw, BjornMeat, MooseHide, MooseSinew, MooseMeat, SealHide, SealBlubber, Kale, KaleSeeds, Oat, OatSeeds, OatFlour, Poteitr, PoteitrSeeds, Lingonberry, MushroomSmokePuff, MushroomBzerker, FirConeFrost, GlowWorm, CelestialFeather, GiantBloodSack, HatefulBlood, NornThread, ElakingHairBundle, CuredSquirrelHamstring, Ectoplasm, Voidplasm, WrithanRoots, FrozenKingDrop, ArmorDeepNorth*, ArmorBerserker*, ArmorGold*, HelmetDN*, HelmetBerserker*, CapeDeepNorth*, TrophyBjorn*, TrophyMoose, TrophySeal, TrophyMole, TrophyFrostTroll, TrophyJotun*, TrophyElaking, TrophyWrithan, TrophyBarka, TrophyBlob_Frost, TrophyBlob_Morkhalla, *Gold*, IceShoes, IceSkates, SaddleMoose, Scythe, Shovel, Lantern_DN, StaffFrostOrbs*, StaffOrbofAhri*, StaffSpiritCaller*, StaffThunderBlood*, FistBjorn*, BakedPoteitr*, KaleChips*, MooseKebab, PulledBear, SealSoup, MeatballsMashedPoteitr, OatmealLingonberryJam, OvenPancake*, Pancakes, SmokedMooseMeat, VikingCupcake*, Lingondricka, OatMilk, ShocklateSmoothie, SpiceDeepNorth, FeastDeepNorth_Material"), ("Ocean", "type:Fish, FishRaw, FishAnglerRaw, FishCooked, FishSoup, SmokedFish, SerpentMeat, SerpentMeatCooked, SerpentStew, SerpentScale, Chitin, TrophySerpent, FishingRod, FishingBait*, SpearChitin, KnifeChitin, ShieldSerpentscale, FreshSeaweed, SpiceOceans, FeastOceans_Material") }; internal DepositGroups(ItemPullPlugin plugin) { this.plugin = plugin; ConfigFile config = ((BaseUnityPlugin)plugin).Config; Enabled = config.Bind<bool>("Grouping", "Enabled", true, "Allow deposits into chests containing other items in the same group. False restores exact-item-only deposits."); UseBiomeGroups = config.Bind<bool>("Grouping", "UseBiomeGroups", false, "Use biome lists instead of standard categories. Grouping must be enabled. Custom groups apply in either mode. Biomes describe item origin/progression, not chest location."); ApplyToMiddleClick = config.Bind<bool>("Grouping", "ApplyToMiddleClick", true, "Use group routing for the single-stack deposit shortcut too. False keeps that shortcut exact-item-only; Deposit All still uses Grouping / Enabled."); (string, string)[] standardDefaults = StandardDefaults; for (int i = 0; i < standardDefaults.Length; i++) { (string, string) tuple = standardDefaults[i]; Standard.Add(new Group(config, $"Groups.{Standard.Count + 1:00} {tuple.Item1}", tuple.Item1, tuple.Item2)); } standardDefaults = BiomeDefaults; for (int i = 0; i < standardDefaults.Length; i++) { (string, string) tuple2 = standardDefaults[i]; Biomes.Add(new Group(config, $"BiomeGroups.{Biomes.Count + 1:00} {tuple2.Item1}", tuple2.Item1, tuple2.Item2)); } for (int j = 1; j <= 5; j++) { Custom.Add(new Group(config, $"CustomGroups.{j:00}", "", "")); } foreach (Group item in Standard.Concat(Biomes).Concat(Custom)) { item.Name.SettingChanged += delegate { dirty = true; }; item.Items.SettingChanged += delegate { dirty = true; }; } UseBiomeGroups.SettingChanged += delegate { dirty = true; }; } internal string? GroupOf(ItemData item) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (dirty) { Rebuild(); } (string, string, ItemType) key = (PrefabName(item), item.m_shared.m_name, item.m_shared.m_itemType); if (itemGroups.TryGetValue(key, out string value)) { return value; } string text = null; foreach (var rule in rules) { if (rule.Rules.Any((Func<ItemData, bool> match) => match(item))) { (text, _) = rule; break; } } itemGroups[key] = text; return text; } private void Rebuild() { //IL_012c: Unknown result type (might be due to invalid IL or missing references) rules.Clear(); itemGroups.Clear(); dirty = false; foreach (Group item in Custom.Concat(UseBiomeGroups.Value ? Biomes : Standard)) { if (string.IsNullOrWhiteSpace(item.Name.Value)) { continue; } List<Func<ItemData, bool>> list = new List<Func<ItemData, bool>>(); foreach (string item2 in from t in item.Items.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries) select t.Trim() into t where t.Length > 0 select t) { if (item2.StartsWith("type:", StringComparison.OrdinalIgnoreCase)) { if (Enum.TryParse<ItemType>(item2.Substring(5), ignoreCase: true, out ItemType type) && Enum.IsDefined(typeof(ItemType), type)) { list.Add((ItemData item) => item.m_shared.m_itemType == type); } } else { Regex pattern = new Regex("^" + Regex.Escape(item2).Replace("\\*", ".*") + "$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); list.Add((ItemData item) => pattern.IsMatch(PrefabName(item)) || pattern.IsMatch(item.m_shared.m_name)); } } if (list.Count > 0) { rules.Add((item.Id, list.ToArray())); } } } internal static string PrefabName(ItemData item) { if (!Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return item.m_shared.m_name; } return ((Object)item.m_dropPrefab).name.Replace("(Clone)", "").Trim(); } internal int Rank(Container chest, ItemData item, bool batch) { List<ItemData> allItems = chest.GetInventory().GetAllItems(); if (allItems.Any(new ItemKey(item).Matches)) { return 0; } if (!Enabled.Value || (!batch && !ApplyToMiddleClick.Value) || allItems.Count == 0) { return -1; } string group = GroupOf(item); if (group == null) { return -1; } if (!allItems.All((ItemData i) => GroupOf(i) == group)) { return -1; } return 1; } internal SearchResult? Destinations(ItemData item, bool batch) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return null; } SearchResult searchResult = new SearchResult { Key = new ItemKey(item), Name = Localization.instance.Localize(item.m_shared.m_name) }; List<(Container, int)> list = new List<(Container, int)>(); foreach (Container item2 in plugin.Search.Accessible(localPlayer)) { item2.Load(); int num = Rank(item2, item, batch); if (num >= 0) { list.Add((item2, num)); } } searchResult.Chests.AddRange(from c in list orderby c.Rank select c.Chest); if (searchResult.Chests.Count <= 0) { return null; } return searchResult; } } internal sealed class DepositInput { private readonly ItemPullPlugin plugin; private readonly List<RaycastResult> hits = new List<RaycastResult>(); private int handledFrame = -1; internal DepositInput(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Tick(InventoryGui gui) { //IL_000b: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) bool flag = ShortcutPressed(plugin.LockShortcut.Value, down: true); if ((flag || ShortcutPressed(plugin.DepositShortcut.Value, down: true)) && Eligible(gui)) { ItemData val = HoveredItem(gui, Vector2.op_Implicit(ZInput.pointerPosition)); if (val != null) { Handle(val, flag); } } } internal bool Eligible(InventoryGui gui) { if (!Object.op_Implicit((Object)(object)gui) || !InventoryGui.IsVisible() || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || ((Character)Player.m_localPlayer).IsDead() || ((Character)Player.m_localPlayer).IsTeleporting() || gui.m_dragItem != null || plugin.Panel.IsTyping || (Object.op_Implicit((Object)(object)gui.m_splitDialog) && gui.m_splitDialog.IsActive) || (Object.op_Implicit((Object)(object)gui.m_variantDialog) && ((Component)gui.m_variantDialog).gameObject.activeSelf) || Menu.IsVisible() || Console.IsVisible() || (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus())) { return false; } GameObject val = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null); if (Object.op_Implicit((Object)(object)val)) { TMP_InputField component = val.GetComponent<TMP_InputField>(); InputField component2 = val.GetComponent<InputField>(); if ((Object.op_Implicit((Object)(object)component) && component.isFocused) || (Object.op_Implicit((Object)(object)component2) && component2.isFocused)) { return false; } } return true; } internal ItemData? HoveredItem(InventoryGui gui, Vector2 pointer) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown //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_0099: 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) InventoryGrid playerGrid = gui.m_playerGrid; if (!Object.op_Implicit((Object)(object)playerGrid) || !((Component)playerGrid).gameObject.activeInHierarchy || playerGrid.GetInventory() != ((Humanoid)Player.m_localPlayer).GetInventory() || !Object.op_Implicit((Object)(object)EventSystem.current)) { return null; } hits.Clear(); EventSystem.current.RaycastAll(new PointerEventData(EventSystem.current) { position = pointer }, hits); if (hits.Count != 0) { RaycastResult val = hits[0]; if (!((Object)(object)((RaycastResult)(ref val)).gameObject.GetComponentInParent<InventoryGrid>() != (Object)(object)playerGrid)) { return playerGrid.GetItem(new Vector2i(Mathf.RoundToInt(pointer.x), Mathf.RoundToInt(pointer.y))); } } return null; } private void Handle(ItemData item, bool locking = false) { if (handledFrame != Time.frameCount) { handledFrame = Time.frameCount; if (locking) { ItemLocks.Toggle(item); } else { plugin.Pull.StartDeposit(item); } } } internal bool ConsumeMouse(InventoryGui gui, InventoryGrid grid, ItemData item, KeyCode button) { //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) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) KeyboardShortcut value = plugin.LockShortcut.Value; bool flag = ((KeyboardShortcut)(ref value)).MainKey == button && ShortcutPressed(plugin.LockShortcut.Value, down: false); if (!flag) { value = plugin.DepositShortcut.Value; if (((KeyboardShortcut)(ref value)).MainKey != button || !ShortcutPressed(plugin.DepositShortcut.Value, down: false)) { goto IL_0084; } } if (!((Object)(object)grid != (Object)(object)gui.m_playerGrid) && Eligible(gui)) { if (item != null) { Handle(item, flag); } return true; } goto IL_0084; IL_0084: return false; } internal static bool ShortcutPressed(KeyboardShortcut shortcut, bool down) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0023: Unknown result type (might be due to invalid IL or missing references) if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !(down ? ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, true) : ZInput.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey, true))) { return false; } if (((KeyboardShortcut)(ref shortcut)).Modifiers.Any((KeyCode key) => !ZInput.GetKey(key, true))) { return false; } KeyCode[] array = new KeyCode[6]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); return ((IEnumerable<KeyCode>)(object)array).All((KeyCode key) => key == ((KeyboardShortcut)(ref shortcut)).MainKey || ((KeyboardShortcut)(ref shortcut)).Modifiers.Contains(key) || !ZInput.GetKey(key, true)); } } [HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")] internal static class DepositLeftClickPatch { private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item) { return !ItemPullPlugin.Instance.Deposit.ConsumeMouse(__instance, grid, item, (KeyCode)323); } } [HarmonyPatch(typeof(InventoryGui), "OnRightClickItem")] internal static class DepositRightClickPatch { private static bool Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item) { return !ItemPullPlugin.Instance.Deposit.ConsumeMouse(__instance, grid, item, (KeyCode)324); } } internal sealed class InventoryTheme { internal readonly Sprite? Panel; internal readonly Sprite? Button; internal readonly Sprite? Input; internal readonly Sprite? Row; internal readonly Sprite? Braid; internal readonly Sprite? Separator; internal readonly TMP_FontAsset BodyFont; internal readonly TMP_FontAsset TitleFont; internal readonly Material BodyMaterial; internal readonly Material TitleMaterial; internal readonly ColorBlock ButtonColors; internal readonly Color Gold = new Color(1f, 0.77f, 0.43f); internal InventoryTheme(InventoryGui gui) { //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_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) Image[] images = ((Component)gui).GetComponentsInChildren<Image>(true); Panel = Sprite("woodpanel_crafting_240") ?? Sprite("woodpanel_playerinventory"); Button = Sprite("button"); Input = Sprite("InputFieldBackground"); Row = Sprite("item_background"); Braid = Sprite("BraidLineHorisontalMedium"); Separator = Sprite("panel_separator"); TMP_Text val = (Object.op_Implicit((Object)(object)gui.m_recipeDecription) ? gui.m_recipeDecription : gui.m_playerName); TMP_Text val2 = (Object.op_Implicit((Object)(object)gui.m_recipeName) ? gui.m_recipeName : gui.m_playerName); BodyFont = val.font; BodyMaterial = val.fontSharedMaterial; TitleFont = val2.font; TitleMaterial = val2.fontSharedMaterial; ButtonColors = ((Selectable)gui.m_craftButton).colors; Sprite? Sprite(string name) { Image? obj = ((IEnumerable<Image>)images).FirstOrDefault((Func<Image, bool>)((Image i) => Object.op_Implicit((Object)(object)i.sprite) && ((Object)i.sprite).name == name)); if (obj == null) { return null; } return obj.sprite; } } internal static void Paint(Image image, Sprite? sprite, Color color) { //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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) image.sprite = sprite; image.type = (Type)((Object.op_Implicit((Object)(object)sprite) && sprite.border != Vector4.zero) ? 1 : 0); ((Graphic)image).color = color; } } internal static class ItemLocks { internal const string DataKey = "Dyls123.ItemPull.DepositLocked"; internal static bool IsLocked(ItemData item) { return item.m_customData.ContainsKey("Dyls123.ItemPull.DepositLocked"); } internal static void Set(ItemData item, bool locked) { if (locked) { item.m_customData["Dyls123.ItemPull.DepositLocked"] = "1"; } else { item.m_customData.Remove("Dyls123.ItemPull.DepositLocked"); } } internal static void Toggle(ItemData item) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && ((Humanoid)localPlayer).GetInventory().ContainsItem(item)) { bool flag = !IsLocked(item); Set(item, flag); ((Humanoid)localPlayer).GetInventory().Changed(false, false); if (Object.op_Implicit((Object)(object)MessageHud.instance)) { ((Character)localPlayer).Message((MessageType)1, Localization.instance.Localize(item.m_shared.m_name) + ": deposit " + (flag ? "locked" : "unlocked") + ".", 0, (Sprite)null, false); } } } internal static void Render(InventoryGrid grid, Player player) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)grid) || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || grid.GetInventory() != ((Humanoid)player).GetInventory()) { return; } foreach (InventoryElement element in grid.m_elements) { ItemData itemAt = grid.GetInventory().GetItemAt(element.Position.x, element.Position.y); bool flag = itemAt != null && IsLocked(itemAt); Transform val = ((Component)element).transform.Find("ItemPull lock"); if (!Object.op_Implicit((Object)(object)val) && flag) { GameObject val2 = new GameObject("ItemPull lock", new Type[1] { typeof(RectTransform) }) { layer = ((Component)element).gameObject.layer }; RectTransform component = val2.GetComponent<RectTransform>(); ((Transform)component).SetParent(((Component)element).transform, false); Vector2 val3 = (component.pivot = Vector2.zero); Vector2 anchorMin = (component.anchorMax = val3); component.anchorMin = anchorMin; component.anchoredPosition = new Vector2(3f, 2f); component.sizeDelta = new Vector2(28f, 22f); TextMeshProUGUI obj = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = element.m_amount.font; ((TMP_Text)obj).fontSharedMaterial = element.m_amount.fontSharedMaterial; ((TMP_Text)obj).text = "[L]"; ((TMP_Text)obj).fontSize = 16f; ((Graphic)obj).color = new Color(1f, 0.77f, 0.43f); ((TMP_Text)obj).alignment = (TextAlignmentOptions)257; ((Graphic)obj).raycastTarget = false; val = (Transform)(object)component; } if (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.SetActive(flag); val.SetAsLastSibling(); } if (flag && Object.op_Implicit((Object)(object)element.m_tooltip) && !element.m_tooltip.m_text.Contains("Deposit locked")) { UITooltip tooltip = element.m_tooltip; tooltip.m_text += "\n<color=#ffca70>Deposit locked</color>"; } } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateInventory")] internal static class LockMarkerPatch { private static void Postfix(InventoryGrid __instance, Player player) { ItemLocks.Render(__instance, player); } } [HarmonyPatch] internal static class LockMergePatch { [ThreadStatic] internal static bool IncomingLocked; private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null); yield return AccessTools.Method(typeof(Inventory), "AddItem", new Type[2] { typeof(ItemData), typeof(Vector2i) }, (Type[])null); yield return AccessTools.Method(typeof(Inventory), "AddItem", new Type[5] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) }, (Type[])null); } private static void Prefix(ItemData item, out bool __state) { __state = IncomingLocked; IncomingLocked = ItemLocks.IsLocked(item); } private static Exception? Finalizer(Exception? __exception, bool __state) { IncomingLocked = __state; return __exception; } } [HarmonyPatch(typeof(Inventory), "FindFreeStackItem")] internal static class LockAutoMergePatch { private static void Postfix(ItemData? __result) { if (__result != null && LockMergePatch.IncomingLocked) { ItemLocks.Set(__result, locked: true); } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) })] internal static class LockSlotMergePatch { private static void Prefix(Inventory __instance, ItemData item, int amount, int x, int y, bool skipValidPositionCheck) { if (amount > 0 && item.m_stack > 0 && x >= 0 && y >= 0 && x < __instance.GetWidth() && (y < __instance.GetHeight() || skipValidPositionCheck)) { ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt != null && itemAt.m_stack < itemAt.m_shared.m_maxStackSize && itemAt.IsSameType(item) && ItemLocks.IsLocked(item)) { ItemLocks.Set(itemAt, locked: true); } } } } [BepInPlugin("Dyls123.ItemPull", "ItemPull", "0.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInProcess("valheim.exe")] [BepInProcess("valheim.x86_64")] public sealed class ItemPullPlugin : BaseUnityPlugin { public const string PluginId = "Dyls123.ItemPull"; public const string PluginVersion = "0.4.1"; internal ConfigEntry<float> Radius; internal ConfigEntry<float> LocateSeconds; internal ConfigEntry<KeyboardShortcut> DepositShortcut; internal ConfigEntry<KeyboardShortcut> LockShortcut; internal ConfigEntry<bool> CraftFromChests; internal ConfigEntry<bool> BuildFromChests; internal ResourceService Resources; internal DepositInput Deposit; internal DepositGroups Groups; internal ChestSearch Search; internal PullService Pull; internal SearchPanel Panel; internal ChestLocator Locator; private Harmony? harmony; internal static ItemPullPlugin Instance { get; private set; } private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown Instance = this; Radius = ((BaseUnityPlugin)this).Config.Bind<float>("Search", "Radius", 60f, new ConfigDescription("Search radius in metres, measured from your character. Only loaded chests are searched.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); LocateSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Locate", "Duration", 4f, new ConfigDescription("Seconds to show chest outlines and distance labels after Locate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>())); UpgradeDefaults(((BaseUnityPlugin)this).Config, Radius, LocateSeconds); DepositShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "DepositItem", new KeyboardShortcut((KeyCode)325, Array.Empty<KeyCode>()), "Deposit the hovered player-inventory stack into nearby matching chests, including while a container is open. Group routing is controlled by Grouping. Use None to disable; supports modifiers."); LockShortcut = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "LockItem", new KeyboardShortcut((KeyCode)325, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Toggle the hovered stack's deposit lock. Locks survive saves, moves and splits. Use None to disable."); CraftFromChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Resources", "CraftFromChests", true, "Use accessible nearby chest resources for crafting and upgrades, using Search / Radius."); BuildFromChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Resources", "BuildFromChests", true, "Use accessible nearby chest resources for building, using Search / Radius."); Search = new ChestSearch(this); Groups = new DepositGroups(this); Pull = new PullService(this); Deposit = new DepositInput(this); Locator = new ChestLocator(this); Panel = new SearchPanel(this); Resources = new ResourceService(this); harmony = new Harmony("Dyls123.ItemPull"); harmony.PatchAll(typeof(ItemPullPlugin).Assembly); Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); foreach (Container chest in array) { Search.Register(chest); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"ItemPull loaded. Open inventory and select ItemPull."); } private void Update() { Panel.Tick(); Locator.Tick(); } private void OnGUI() { Locator.Draw(); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); Panel.Dispose(); Locator.Clear(); Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal void Error(Exception exception) { ((BaseUnityPlugin)this).Logger.LogError((object)exception); } internal void CompatibilityWarning() { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Valheim Plus resource configuration is unavailable. ItemPull defers chest crafting/building to Valheim Plus to prevent conflicting consumption."); } internal static void UpgradeDefaults(ConfigFile config, ConfigEntry<float> radius, ConfigEntry<float> duration) { ConfigEntry<int> val = config.Bind<int>("Internal", "DefaultSettingsRevision", 0, "Automatic default migration. Do not edit."); if (val.Value < 1) { if (Mathf.Approximately(radius.Value, 30f)) { radius.Value = 60f; } if (Mathf.Approximately(duration.Value, 20f)) { duration.Value = 4f; } val.Value = 1; } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { ItemPullPlugin.Instance.Search.Register(__instance); } } [HarmonyPatch(typeof(Container), "RPC_OpenResponse")] internal static class OpenResponsePatch { private static bool Prefix(Container __instance, long uid, bool granted) { return !ItemPullPlugin.Instance.Pull.Receive(__instance, uid, granted); } } [HarmonyPatch(typeof(InventoryGui), "Show")] internal static class InventoryShowPatch { private static void Postfix(InventoryGui __instance) { ItemPullPlugin.Instance.Panel.Ensure(__instance); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] internal static class InventoryHidePatch { private static void Prefix() { ItemPullPlugin.Instance.Panel.Close(); ItemPullPlugin.Instance.Pull.Cancel(); } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class InventoryTypingPatch { private static void Prefix(InventoryGui __instance) { ItemPullPlugin.Instance.Deposit.Tick(__instance); if (ItemPullPlugin.Instance.Panel.IsTyping) { ZInput.ResetButtonStatus("Inventory"); ZInput.ResetButtonStatus("Use"); } } } internal sealed class PullService { private sealed class Request { internal long Owner; internal bool Received; internal bool Granted; } private readonly ItemPullPlugin plugin; private readonly Dictionary<Container, Request> requests = new Dictionary<Container, Request>(); private int generation; internal bool Busy { get; private set; } internal PullService(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Cancel() { generation++; } internal bool Receive(Container chest, long sender, bool granted) { if (!requests.TryGetValue(chest, out Request value) || value.Owner != sender) { return false; } value.Received = true; value.Granted = granted; requests.Remove(chest); return true; } internal void Start(SearchResult result, int quantity) { if (!Busy && quantity > 0 && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { Busy = true; ((MonoBehaviour)plugin).StartCoroutine(Run(result, quantity, generation)); } } internal bool StartDeposit(ItemData item) { Player localPlayer = Player.m_localPlayer; if (Busy || !Object.op_Implicit((Object)(object)localPlayer) || item == null || item.m_stack <= 0 || item.m_equipped || item.m_shared.m_questItem || ItemLocks.IsLocked(item) || !((Humanoid)localPlayer).GetInventory().ContainsItem(item)) { return false; } SearchResult searchResult = plugin.Groups.Destinations(item, batch: false); if (searchResult == null) { return false; } Busy = true; ((MonoBehaviour)plugin).StartCoroutine(RunTransfer(searchResult, item.m_stack, generation, item)); return true; } private IEnumerator Run(SearchResult result, int quantity, int ticket) { return RunTransfer(result, quantity, ticket, null); } internal void StartDepositAll() { Player localPlayer = Player.m_localPlayer; if (!Busy && Object.op_Implicit((Object)(object)localPlayer) && InventoryGui.IsVisible()) { ItemData[] items = (from i in ((Humanoid)localPlayer).GetInventory().GetAllItems() where !i.m_equipped && !i.m_shared.m_questItem && !ItemLocks.IsLocked(i) select i).ToArray(); Busy = true; ((MonoBehaviour)plugin).StartCoroutine(DepositAll(items, generation)); } } private IEnumerator DepositAll(ItemData[] items, int ticket) { int moved = 0; try { foreach (ItemData item in items) { Player localPlayer = Player.m_localPlayer; if (ticket != generation || !Object.op_Implicit((Object)(object)localPlayer) || !InventoryGui.IsVisible()) { break; } if (!((Humanoid)localPlayer).GetInventory().ContainsItem(item) || item.m_equipped || ItemLocks.IsLocked(item)) { continue; } SearchResult searchResult = plugin.Groups.Destinations(item, batch: true); if (searchResult == null) { continue; } int before = item.m_stack; { IEnumerator transfer = RunTransfer(searchResult, before, ticket, item, batch: true); try { while (transfer.MoveNext()) { yield return transfer.Current; } } finally { IDisposable disposable = transfer as IDisposable; if (disposable != null) { disposable.Dispose(); } } } moved += before - item.m_stack; Busy = true; } } finally { PullService pullService = this; pullService.Busy = false; pullService.plugin.Resources.Invalidate(); string text = $"Deposit All: {moved} item(s) deposited." + ((ticket != pullService.generation) ? " Deposit cancelled." : " Locked, equipped and unmatched items stay in your inventory."); pullService.plugin.Panel.Refresh(); pullService.plugin.Panel.Status(text); if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)MessageHud.instance)) { ((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } } internal bool WithAccess(IEnumerable<Container> chests, Func<bool> valid, Action<List<Container>> execute) { if (Busy) { return false; } Busy = true; ((MonoBehaviour)plugin).StartCoroutine(Access(chests.ToArray(), generation, valid, execute)); return true; } private IEnumerator Access(Container[] chests, int ticket, Func<bool> valid, Action<List<Container>> execute) { List<Container> held = new List<Container>(); Player player = Player.m_localPlayer; try { foreach (Container chest in chests) { if (ticket != generation || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || !valid()) { yield break; } if (plugin.Search.CanAccess(chest, player) && !InUse(chest) && !requests.ContainsKey(chest)) { Request request = new Request { Owner = chest.m_nview.GetZDO().GetOwner() }; requests[chest] = request; chest.m_nview.InvokeRPC("RPC_RequestOpen", new object[1] { player.GetPlayerID() }); float deadline = Time.realtimeSinceStartup + 5f; while (ticket == generation && !request.Received && Object.op_Implicit((Object)(object)chest) && valid() && Time.realtimeSinceStartup < deadline) { yield return null; } while (ticket == generation && request.Granted && Object.op_Implicit((Object)(object)chest) && !chest.IsOwner() && valid() && Time.realtimeSinceStartup < deadline) { yield return null; } if (ticket != generation || !valid()) { yield break; } if (request.Received && request.Granted && Object.op_Implicit((Object)(object)chest) && chest.IsOwner() && !InUse(chest) && plugin.Search.CanAccess(chest, player)) { chest.Load(); chest.SetInUse(true); held.Add(chest); } } } if (ticket == generation && valid() && held.All((Container c) => Object.op_Implicit((Object)(object)c) && c.IsOwner() && plugin.Search.CanAccess(c, player))) { execute(held); } } finally { PullService pullService = this; foreach (Container item in held) { if (Object.op_Implicit((Object)(object)item) && item.IsOwner()) { item.SetInUse(false); } } pullService.Busy = false; pullService.plugin.Resources.Invalidate(); } } private IEnumerator RunTransfer(SearchResult result, int quantity, int ticket, ItemData? deposit, bool batch = false) { Player player = Player.m_localPlayer; int moved = 0; int skipped = 0; try { requests.Keys.Where((Container c) => !Object.op_Implicit((Object)(object)c)).ToList().ForEach(delegate(Container c) { requests.Remove(c); }); Container[] array = result.Chests.ToArray(); foreach (Container chest in array) { if (ticket != generation || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !InventoryGui.IsVisible() || moved >= quantity || (deposit != null && (!((Humanoid)player).GetInventory().ContainsItem(deposit) || deposit.m_equipped || ItemLocks.IsLocked(deposit)))) { break; } bool alreadyOpen = deposit != null && IsOwnOpenChest(chest); if (!plugin.Search.CanAccess(chest, player) || (InUse(chest) && !alreadyOpen) || requests.ContainsKey(chest)) { skipped++; continue; } if (deposit != null) { chest.Load(); if (plugin.Groups.Rank(chest, deposit, batch) < 0) { continue; } } if (!alreadyOpen) { Request request = new Request { Owner = chest.m_nview.GetZDO().GetOwner() }; requests[chest] = request; plugin.Panel.Status("Requesting " + Localization.instance.Localize(chest.m_name) + "…"); chest.m_nview.InvokeRPC("RPC_RequestOpen", new object[1] { player.GetPlayerID() }); float deadline = Time.realtimeSinceStartup + 5f; while (ticket == generation && !request.Received && Object.op_Implicit((Object)(object)chest) && Time.realtimeSinceStartup < deadline) { yield return null; } while (ticket == generation && request.Granted && Object.op_Implicit((Object)(object)chest) && !chest.IsOwner() && Time.realtimeSinceStartup < deadline) { yield return null; } if (!request.Received || !request.Granted || !Object.op_Implicit((Object)(object)chest) || !chest.IsOwner()) { skipped++; continue; } } if (ticket != generation || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !InventoryGui.IsVisible()) { break; } if (!plugin.Search.CanAccess(chest, player) || (InUse(chest) && !alreadyOpen)) { skipped++; continue; } chest.Load(); if (deposit != null && (!((Humanoid)player).GetInventory().ContainsItem(deposit) || deposit.m_equipped || ItemLocks.IsLocked(deposit) || !result.Key.Matches(deposit))) { break; } if (deposit != null && plugin.Groups.Rank(chest, deposit, batch) < 0) { continue; } if (!alreadyOpen) { chest.SetInUse(true); } try { moved += ((deposit == null) ? MoveMatching(chest.GetInventory(), ((Humanoid)player).GetInventory(), result.Key, quantity - moved) : MoveExact(((Humanoid)player).GetInventory(), chest.GetInventory(), deposit, quantity - moved)); } finally { if (!alreadyOpen && Object.op_Implicit((Object)(object)chest) && chest.IsOwner()) { chest.SetInUse(false); } } } } finally { PullService pullService = this; pullService.Busy = batch; pullService.plugin.Resources.Invalidate(); pullService.plugin.Panel.Refresh(); string text = string.Format("{0} {1} / {2} {3}.", (deposit == null) ? "Pulled" : "Deposited", moved, quantity, result.Name) + ((ticket != pullService.generation) ? " Transfer cancelled." : ((skipped > 0) ? $" {skipped} chest(s) unavailable." : ((moved < quantity) ? " No more matching items or space." : ""))); pullService.plugin.Panel.Status(text); if (deposit != null && !batch && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && Object.op_Implicit((Object)(object)MessageHud.instance)) { ((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false); } } } private static bool InUse(Container chest) { if (!chest.IsInUse()) { return chest.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 0; } return true; } private static bool IsOwnOpenChest(Container chest) { if (Object.op_Implicit((Object)(object)InventoryGui.instance) && (Object)(object)InventoryGui.instance.m_currentContainer == (Object)(object)chest) { return chest.IsOwner(); } return false; } internal static int MoveMatching(Inventory source, Inventory destination, ItemKey key, int quantity) { int num = 0; ItemData[] array = source.GetAllItems().Where(((ItemKey)key).Matches).ToArray(); foreach (ItemData item in array) { num += MoveExact(source, destination, item, quantity - num); if (num >= quantity) { break; } } return num; } internal static int MoveExact(Inventory source, Inventory destination, ItemData item, int quantity) { //IL_0009: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0074: Unknown result type (might be due to invalid IL or missing references) int num = 0; while (source.ContainsItem(item) && item.m_stack > 0 && num < quantity) { Vector2i val = FindSlot(destination, item); if (val.x < 0) { return num; } ItemData itemAt = destination.GetItemAt(val.x, val.y); int val2 = item.m_shared.m_maxStackSize - (itemAt?.m_stack ?? 0); int num2 = Math.Min(quantity - num, Math.Min(item.m_stack, val2)); if (num2 <= 0) { return num; } int stack = item.m_stack; destination.MoveItemToThis(source, item, num2, val.x, val.y); int num3 = stack - item.m_stack; num += num3; if (num3 <= 0) { return num; } } return num; } private static Vector2i FindSlot(Inventory inventory, ItemData item) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.IsSameType(item) && allItem.m_stack < allItem.m_shared.m_maxStackSize) { return allItem.m_gridPos; } } for (int i = 0; i < inventory.GetHeight(); i++) { for (int j = 0; j < inventory.GetWidth(); j++) { if (inventory.GetItemAt(j, i) == null) { return new Vector2i(j, i); } } } return new Vector2i(-1, -1); } } internal static class ResourceCompatibility { internal const string ValheimPlusId = "org.bepinex.plugins.valheim_plus"; private static readonly Type? Configuration = AccessTools.TypeByName("ValheimPlus.Configurations.Configuration"); private static readonly PropertyInfo? Current = Configuration?.GetProperty("Current"); private static readonly PropertyInfo? CraftFromChest = Configuration?.GetProperty("CraftFromChest"); private static readonly PropertyInfo? Enabled = CraftFromChest?.PropertyType.GetProperty("IsEnabled"); private static bool warned; internal static bool ValheimPlusHandlesResources { get { if (Configuration == null) { return false; } try { object obj = Current?.GetValue(null); object obj2 = ((obj == null) ? null : CraftFromChest?.GetValue(obj)); if (obj2 != null) { object obj3 = Enabled?.GetValue(obj2); if (obj3 is bool) { return (bool)obj3; } } } catch (Exception exception) { if (!warned) { ItemPullPlugin.Instance.Error(exception); } } if (!warned) { warned = true; ItemPullPlugin.Instance.CompatibilityWarning(); } return true; } } } internal sealed class ResourceService { private readonly ItemPullPlugin plugin; private List<Container> cached = new List<Container>(); private Player? cachedPlayer; private Vector3 cachedPosition; private float cacheUntil; private float cachedRadius; private List<Container>? transaction; [ThreadStatic] internal static int ReadDepth; [ThreadStatic] internal static int Suppress; internal bool Executing => transaction != null; internal bool CraftEnabled { get { if (plugin.CraftFromChests.Value) { return !ResourceCompatibility.ValheimPlusHandlesResources; } return false; } } internal bool BuildEnabled { get { if (plugin.BuildFromChests.Value) { return !ResourceCompatibility.ValheimPlusHandlesResources; } return false; } } internal ResourceService(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Invalidate() { cacheUntil = -1f; } internal List<Container> Sources() { //IL_0073: 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_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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) Player player = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)player)) { return new List<Container>(); } if (transaction != null) { return transaction; } if (!(Time.unscaledTime >= cacheUntil) && !((Object)(object)cachedPlayer != (Object)(object)player) && cachedRadius == plugin.Radius.Value) { Vector3 val = cachedPosition - ((Component)player).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude > 0.25f)) { goto IL_0161; } } cached = (from c in plugin.Search.Accessible(player) where !InUse(c) select c).ToList(); foreach (Container item in cached) { item.Load(); } cacheUntil = Time.unscaledTime + 0.4f; cachedPlayer = player; cachedPosition = ((Component)player).transform.position; cachedRadius = plugin.Radius.Value; goto IL_0161; IL_0161: return cached.Where((Container c) => plugin.Search.CanAccess(c, player) && !InUse(c)).ToList(); } private static bool InUse(Container chest) { if (!chest.IsInUse()) { return chest.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) != 0; } return true; } internal static bool Matches(ItemData item, string? name, int quality, bool world) { if ((name == null || item.m_shared.m_name == name) && (quality < 0 || item.m_quality == quality)) { if (world) { return item.m_worldLevel >= Game.m_worldLevel; } return true; } return false; } internal static int OwnCount(Inventory inventory, string? name, int quality = -1, bool world = true) { return (from i in inventory.GetAllItems() where Matches(i, name, quality, world) select i).Sum((ItemData i) => i.m_stack); } internal int RemoteCount(string? name, int quality, bool world) { return Sources().Sum((Container c) => OwnCount(c.GetInventory(), name, quality, world)); } internal int Total(string name, int quality = -1) { return OwnCount(((Humanoid)Player.m_localPlayer).GetInventory(), name, quality) + RemoteCount(name, quality, world: true); } internal ItemData? FirstIngredient(Player player, Recipe recipe, int quality, int multiplier, out int amount, out int extra) { foreach (Requirement item in Active(player, recipe.m_resources)) { int num = item.GetAmount(quality) * multiplier; if (num <= 0) { continue; } string name = item.m_resItem.m_itemData.m_shared.m_name; int q; for (q = 0; q <= item.m_resItem.m_itemData.m_shared.m_maxQuality; q++) { if (Total(name, q) >= num) { ItemData val = ((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Matches(i, name, q, world: true))) ?? Sources().SelectMany((Container c) => c.GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => Matches(i, name, q, world: true))); if (val != null) { amount = num; extra = item.m_extraAmountOnlyOneIngredient; return val; } } } } amount = (extra = 0); return null; } private static IEnumerable<Requirement> Active(Player player, Requirement[] requirements) { CraftingStation station = player.GetCurrentCraftingStation(); return requirements.Where((Requirement r) => Object.op_Implicit((Object)(object)r.m_resItem) && ((!Object.op_Implicit((Object)(object)station)) ? (!r.m_upgraderResource) : (station.m_upgrader == r.m_upgraderResource))); } private bool PersonalRecipe(Player player, Recipe recipe, int quality, int multiplier) { Suppress++; try { return player.HaveRequirements(recipe, false, quality, multiplier); } finally { Suppress--; } } internal bool BeginCraft(InventoryGui gui, Player player) { //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) Recipe recipe = gui.m_craftRecipe; if (Executing || !CraftEnabled || (Object)(object)player != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)recipe) || player.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25)) { return true; } int quality = ((gui.m_craftUpgradeItem == null) ? 1 : (gui.m_craftUpgradeItem.m_quality + 1)); int multiplier = ((!gui.m_multiCrafting) ? 1 : gui.m_multiCraftAmount); if (PersonalRecipe(player, recipe, quality, multiplier)) { Execute(new List<Container>(), delegate { gui.DoCrafting(player); }); return false; } if (plugin.Pull.Busy) { return false; } ItemData upgrade = gui.m_craftUpgradeItem; CraftingStation station = player.GetCurrentCraftingStation(); int variant = gui.m_craftVariant; RecipeDataPair selection = gui.m_selectedRecipe; Invalidate(); HashSet<string> names = new HashSet<string>(from r in Active(player, recipe.m_resources) where r.GetAmount(quality) > 0 select r.m_resItem.m_itemData.m_shared.m_name); Container[] chests = (from c in Sources() where c.GetInventory().GetAllItems().Any((ItemData i) => names.Contains(i.m_shared.m_name)) select c).ToArray(); plugin.Pull.WithAccess(chests, Valid, delegate(List<Container> held) { Execute(held, delegate { if (!player.HaveRequirements(recipe, false, quality, multiplier)) { Missing(player); } else { gui.DoCrafting(player); } }); }); return false; bool Valid() { if (CraftEnabled && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && Object.op_Implicit((Object)(object)gui) && (Object)(object)InventoryGui.instance == (Object)(object)gui && InventoryGui.IsVisible() && (Object)(object)gui.m_craftRecipe == (Object)(object)recipe && (Object)(object)((RecipeDataPair)(ref gui.m_selectedRecipe)).Recipe == (Object)(object)((RecipeDataPair)(ref selection)).Recipe && ((RecipeDataPair)(ref gui.m_selectedRecipe)).ItemData == ((RecipeDataPair)(ref selection)).ItemData && gui.m_craftUpgradeItem == upgrade && (upgrade == null || ((Humanoid)player).GetInventory().ContainsItem(upgrade)) && (Object)(object)player.GetCurrentCraftingStation() == (Object)(object)station && gui.m_craftVariant == variant) { return ((!gui.m_multiCrafting) ? 1 : gui.m_multiCraftAmount) == multiplier; } return false; } } internal bool BeginBuild(Player player, Piece piece) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0115: Unknown result type (might be due to invalid IL or missing references) if (Executing || !BuildEnabled || (Object)(object)player != (Object)(object)Player.m_localPlayer || player.m_noPlacementCost || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) { return true; } Requirement[] source = piece.m_resources.Where((Requirement r) => Object.op_Implicit((Object)(object)r.m_resItem) && r.m_amount > 0).ToArray(); if (source.All((Requirement r) => OwnCount(((Humanoid)player).GetInventory(), r.m_resItem.m_itemData.m_shared.m_name) >= r.m_amount)) { return true; } if (plugin.Pull.Busy) { return false; } player.UpdatePlacementGhost(false); GameObject ghost = player.m_placementGhost; if (!Object.op_Implicit((Object)(object)ghost)) { return false; } Vector3 position = ghost.transform.position; Quaternion rotation = ghost.transform.rotation; ItemData tool = ((Humanoid)player).GetRightItem(); Invalidate(); HashSet<string> names = new HashSet<string>(source.Select((Requirement r) => r.m_resItem.m_itemData.m_shared.m_name)); Container[] chests = (from c in Sources() where c.GetInventory().GetAllItems().Any((ItemData i) => names.Contains(i.m_shared.m_name)) select c).ToArray(); plugin.Pull.WithAccess(chests, Valid, delegate(List<Container> held) { Execute(held, delegate { //IL_0017: 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_0022: 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_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) player.UpdatePlacementGhost(false); Vector3 val = ghost.transform.position - position; if (((Vector3)(ref val)).sqrMagnitude > 0.01f || Quaternion.Angle(ghost.transform.rotation, rotation) > 1f) { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { ((Character)player).Message((MessageType)1, "Build cancelled: placement target moved. Click again.", 0, (Sprite)null, false); } } else if (!player.HaveRequirements(piece, (RequirementMode)0)) { Missing(player); } else { player.m_placePressedTime = Time.time; player.UpdatePlacement(true, 0f); } }); }); return false; bool Valid() { if (BuildEnabled && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).InPlaceMode() && !InventoryGui.IsVisible() && (Object)(object)player.GetSelectedPiece() == (Object)(object)piece && ((Humanoid)player).GetRightItem() == tool && (Object)(object)player.m_placementGhost == (Object)(object)ghost) { return ((Character)player).TakeInput(); } return false; } } internal void Execute(List<Container> held, Action action) { if (transaction != null) { throw new InvalidOperationException("Nested storage resource transaction."); } transaction = held; int readDepth = ReadDepth; ReadDepth++; try { action(); } finally { ReadDepth = readDepth; transaction = null; Invalidate(); } } internal void Consume(Inventory inventory, string name, int amount, int quality, bool world) { if (amount > OwnCount(inventory, name, quality, world) + RemoteCount(name, quality, world)) { throw new InvalidOperationException("Resource transaction lost its validated stock."); } int num = Math.Min(amount, OwnCount(inventory, name, quality, world)); Suppress++; try { inventory.RemoveItem(name, num, quality, world); amount -= num; foreach (Container item in Sources()) { if (amount <= 0) { break; } int num2 = Math.Min(amount, OwnCount(item.GetInventory(), name, quality, world)); if (num2 > 0) { item.GetInventory().RemoveItem(name, num2, quality, world); amount -= num2; } } if (amount > 0) { throw new InvalidOperationException("Resource transaction lost its validated stock."); } } finally { Suppress--; } } private static void Missing(Player player) { if (Object.op_Implicit((Object)(object)MessageHud.instance)) { ((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false); } } } [HarmonyPatch] internal static class ResourceCountScopePatch { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Player), "HaveRequirements", new Type[4] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) }, (Type[])null); yield return AccessTools.Method(typeof(Player), "HaveRequirements", new Type[2] { typeof(Piece), typeof(RequirementMode) }, (Type[])null); yield return AccessTools.Method(typeof(Player), "GetFirstRequiredItem", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(InventoryGui), "SetupRequirement", (Type[])null, (Type[])null); } private static void Prefix(object? __instance, MethodBase __originalMethod, object[] __args, out int __state) { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 __state = ResourceService.ReadDepth; ItemPullPlugin instance = ItemPullPlugin.Instance; if (ResourceService.Suppress > 0) { return; } if (__originalMethod.Name == "HaveRequirements") { if (!((Object)((__instance is Player) ? __instance : null) != (Object)(object)Player.m_localPlayer)) { if (__args[0] is Recipe && !(bool)__args[1] && instance.Resources.CraftEnabled) { ResourceService.ReadDepth++; } if (__args[0] is Piece && (int)(RequirementMode)__args[1] != 1 && instance.Resources.BuildEnabled) { ResourceService.ReadDepth++; } } } else if (__originalMethod.Name == "GetFirstRequiredItem") { if ((Object)((__instance is Player) ? __instance : null) == (Object)(object)Player.m_localPlayer && instance.Resources.CraftEnabled) { ResourceService.ReadDepth++; } } else if ((Object)(Player)__args[2] == (Object)(object)Player.m_localPlayer && (((bool)__args[3]) ? instance.Resources.CraftEnabled : instance.Resources.BuildEnabled)) { ResourceService.ReadDepth++; } } private static Exception? Finalizer(Exception? __exception, int __state) { ResourceService.ReadDepth = __state; return __exception; } } [HarmonyPatch(typeof(Inventory), "CountItems")] internal static class ResourceCountPatch { private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result) { if (ResourceService.ReadDepth > 0 && ResourceService.Suppress == 0 && Object.op_Implicit((Object)(object)Player.m_localPlayer) && __instance == ((Humanoid)Player.m_localPlayer).GetInventory()) { __result += ItemPullPlugin.Instance.Resources.RemoteCount(name, quality, matchWorldLevel); } } } [HarmonyPatch(typeof(Inventory), "HaveItem", new Type[] { typeof(string), typeof(bool) })] internal static class ResourceHaveItemPatch { private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result) { if (!__result && ResourceService.ReadDepth > 0 && ResourceService.Suppress == 0 && Object.op_Implicit((Object)(object)Player.m_localPlayer) && __instance == ((Humanoid)Player.m_localPlayer).GetInventory()) { __result = ItemPullPlugin.Instance.Resources.RemoteCount(name, -1, matchWorldLevel) > 0; } } } [HarmonyPatch(typeof(Player), "GetFirstRequiredItem")] internal static class ResourceFirstIngredientPatch { private static void Postfix(Player __instance, Recipe recipe, int qualityLevel, int craftMultiplier, ref int amount, ref int extraAmount, ref ItemData? __result) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && ItemPullPlugin.Instance.Resources.CraftEnabled && ResourceService.Suppress == 0) { __result = ItemPullPlugin.Instance.Resources.FirstIngredient(__instance, recipe, qualityLevel, craftMultiplier, out amount, out extraAmount); } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class ResourceCraftPatch { private static bool Prefix(InventoryGui __instance, Player player, out ItemData? __state) { __instance.m_craftTimer = -1f; __state = ((__instance.m_craftUpgradeItem != null && ItemLocks.IsLocked(__instance.m_craftUpgradeItem)) ? __instance.m_craftUpgradeItem : null); return ItemPullPlugin.Instance.Resources.BeginCraft(__instance, player); } private static void Postfix(Player player, ItemData? __state) { if (__state != null) { ItemData itemAt = ((Humanoid)player).GetInventory().GetItemAt(__state.m_gridPos.x, __state.m_gridPos.y); if (itemAt != null && itemAt.m_shared.m_name == __state.m_shared.m_name && !ItemLocks.IsLocked(itemAt)) { ItemLocks.Set(itemAt, locked: true); ((Humanoid)player).GetInventory().Changed(false, false); } } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")] internal static class ResourceCraftStartPatch { private static bool Prefix() { return !ItemPullPlugin.Instance.Pull.Busy; } } [HarmonyPatch(typeof(InventoryGui), "UpdateCraftingPanel")] internal static class ResourceCraftButtonPatch { private static void Postfix(InventoryGui __instance) { if (Object.op_Implicit((Object)(object)__instance.m_craftButton) && ItemPullPlugin.Instance.Pull.Busy) { ((Selectable)__instance.m_craftButton).interactable = false; } } } [HarmonyPatch(typeof(InventoryGui), "OnCraftCancelPressed")] internal static class ResourceCraftCancelPatch { private static void Prefix() { ItemPullPlugin.Instance.Pull.Cancel(); } } [HarmonyPatch(typeof(Player), "TryPlacePiece")] internal static class ResourceBuildPatch { private static bool Prefix(Player __instance, Piece piece, ref bool __result) { if (ItemPullPlugin.Instance.Resources.BeginBuild(__instance, piece)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[] { typeof(string), typeof(int), typeof(int), typeof(bool) })] internal static class ResourceConsumePatch { private static bool Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased) { ItemPullPlugin instance = ItemPullPlugin.Instance; if (!instance.Resources.Executing || ResourceService.Suppress > 0 || !Object.op_Implicit((Object)(object)Player.m_localPlayer) || __instance != ((Humanoid)Player.m_localPlayer).GetInventory()) { return true; } instance.Resources.Consume(__instance, name, amount, itemQuality, worldLevelBased); return false; } } internal sealed class SearchPanel : IDisposable { private const int PageSize = 6; private readonly ItemPullPlugin plugin; private GameObject? root; private GameObject? toggle; private GameObject? depositAll; private InventoryTheme theme; private TMP_InputField search; private TMP_InputField amount; private TMP_Text status; private TMP_Text summary; private TMP_Text pages; private TMP_Text locateHint; private Button previous; private Button next; private readonly List<GameObject> rows = new List<GameObject>(); private List<SearchResult> results = new List<SearchResult>(); private int page; private float refreshAt = -1f; private bool wasBusy; internal bool IsTyping { get { if (Object.op_Implicit((Object)(object)root) && root.activeSelf) { if (!search.isFocused) { return amount.isFocused; } return true; } return false; } } internal SearchPanel(ItemPullPlugin plugin) { this.plugin = plugin; } internal void Ensure(InventoryGui gui) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_013a: 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_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)root) && Object.op_Implicit((Object)(object)toggle) && Object.op_Implicit((Object)(object)depositAll)) { return; } Dispose(); theme = new InventoryTheme(gui); Canvas componentInParent = ((Component)gui).GetComponentInParent<Canvas>(true); if (!Object.op_Implicit((Object)(object)componentInParent)) { componentInParent = ((Component)gui.m_player).GetComponentInParent<Canvas>(true); } if (!Object.op_Implicit((Object)(object)componentInParent)) { return; } toggle = Button((Transform)(object)gui.m_player, "ItemPull", -132f, -4f, 124f, 30f, Open); RectTransform component = toggle.GetComponent<RectTransform>(); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(1f, 1f); component.anchorMax = val; component.anchorMin = val; component.anchoredPosition = new Vector2(-132f, 34f); depositAll = Button((Transform)(object)gui.m_player, "Deposit All", 0f, 0f, 124f, 30f, plugin.Pull.StartDepositAll); RectTransform component2 = depositAll.GetComponent<RectTransform>(); ((Vector2)(ref val))..ctor(1f, 1f); component2.anchorMax = val; component2.anchorMin = val; component2.anchoredPosition = new Vector2(-264f, 34f); depositAll.AddComponent<UITooltip>().m_text = "Deposit unlocked stacks into nearby chests: exact items first, then similar groups when enabled. Lock/unlock: " + ((object)plugin.LockShortcut.Value/*cast due to .constrained prefix*/).ToString(); root = Rect(((Component)componentInParent).transform, "ItemPull search", 0f, 0f, 650f, 530f); RectTransform component3 = root.GetComponent<RectTransform>();