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 GrabMaterials v2.6.1
BepInEx/plugins/GrabMaterials.dll
Decompiled 3 weeks 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.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GrabMaterials; using GrabMaterialsMod; using HarmonyLib; using Jotunn; using Jotunn.Configs; using Jotunn.Extensions; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("GrabMaterials")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("2.6.1.0")] [assembly: AssemblyInformationalVersion("2.6.1+bc2d6c3b4a9c96f2053186b72993c2f44c27db20")] [assembly: AssemblyProduct("GrabMaterials")] [assembly: AssemblyTitle("GrabMaterials")] [assembly: AssemblyVersion("2.6.1.0")] namespace GrabMaterialsMod { [BepInPlugin("DeathMonger.GrabMaterialsMod", "Grab Materials", "2.6.1")] [BepInProcess("valheim.exe")] public class GrabMaterialsMod : BaseUnityPlugin { public enum DeltaSetting { UseGlobal, On, Off } public class GrabPackConfig { public ConfigEntry<string> Name; public ConfigEntry<KeyboardShortcut> Key; public ConfigEntry<string> Items; public ConfigEntry<DeltaSetting> GrabDelta; public string Section; public ButtonConfig Button; public bool HasName => !string.IsNullOrWhiteSpace(Name.Value); public bool HasKey { get { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0014: Invalid comparison between Unknown and I4 KeyboardShortcut value = Key.Value; return (int)((KeyboardShortcut)(ref value)).MainKey > 0; } } public GrabPackConfig(ConfigFile config, string section, string name, KeyboardShortcut keyboardShortcut, string items) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0044: 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_005b: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_00d1: Expected O, but got Unknown Section = section; Name = config.Bind<string>(section, section + " Name", name, new ConfigDescription("Name of the grab pack", (AcceptableValueBase)null, Array.Empty<object>())); Key = config.Bind<KeyboardShortcut>(section, section + " Key", keyboardShortcut, new ConfigDescription("Key to grab materials for the grab pack", (AcceptableValueBase)null, Array.Empty<object>())); Items = config.Bind<string>(section, section + " Items", items, new ConfigDescription("Items to grab for the grab pack", (AcceptableValueBase)null, Array.Empty<object>())); GrabDelta = config.Bind<DeltaSetting>(section, section + " Grab Delta", DeltaSetting.UseGlobal, new ConfigDescription("UseGlobal = follow the 'Grab Delta (default)' setting; On = only grab the shortfall (e.g. if the pack needs 10 wood and you have 7, only 3 will be grabbed); Off = always grab the full amount.", (AcceptableValueBase)null, Array.Empty<object>())); Button = new ButtonConfig { Name = section, ShortcutConfig = Key }; } } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static EventHandler <>9__43_0; public static EventHandler <>9__43_1; public static ConsoleEvent <>9__44_0; public static ConsoleEvent <>9__44_1; public static ConsoleEvent <>9__44_2; public static ConsoleEvent <>9__44_3; public static ConsoleEvent <>9__44_4; public static ConsoleEvent <>9__44_5; public static ConsoleEvent <>9__44_6; public static ConsoleEvent <>9__44_7; public static ConsoleEvent <>9__44_8; public static ConsoleEvent <>9__44_9; public static ConsoleEvent <>9__44_10; public static ConsoleEvent <>9__44_11; public static Action <>9__60_1; internal void <InitConfig>b__43_0(object s, EventArgs e) { PanelPause.Refresh(); } internal void <InitConfig>b__43_1(object sender, EventArgs e) { Log.LogInfo((object)("Grabpack renamed " + sender.ToString() + " " + e.ToString())); } internal void <InitCommands>b__44_0(ConsoleEventArgs args) { args.GrabItemsFromNearbyContainers(); } internal void <InitCommands>b__44_1(ConsoleEventArgs args) { args.GrabItemsFromNearbyContainers(); } internal void <InitCommands>b__44_2(ConsoleEventArgs args) { ConsoleCommands.GrabMaterialsForSelectedPiece(); } internal void <InitCommands>b__44_3(ConsoleEventArgs args) { args.GrabMaterialsForPiece(); } internal void <InitCommands>b__44_4(ConsoleEventArgs args) { ListGrabPacks(); } internal void <InitCommands>b__44_5(ConsoleEventArgs args) { ConsoleCommands.ResetPendingLedger(); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "Grab delta ledger cleared.", 0, (Sprite)null, false); } } internal void <InitCommands>b__44_6(ConsoleEventArgs args) { ListLocalInventory(args); } internal void <InitCommands>b__44_7(ConsoleEventArgs args) { ListLocalInventory(args); } internal void <InitCommands>b__44_8(ConsoleEventArgs args) { SetInventoryStyle(args); } internal void <InitCommands>b__44_9(ConsoleEventArgs args) { FindContainersWithMatchingItems(args); } internal void <InitCommands>b__44_10(ConsoleEventArgs args) { FindContainersWithMatchingItems(args); } internal void <InitCommands>b__44_11(ConsoleEventArgs args) { StoreItemsInNearbyContainers(); } internal void <OpenPackEditor>b__60_1() { ListGrabPacks(); } } private const string ModGuid = "DeathMonger.GrabMaterialsMod"; private readonly Harmony harmony = new Harmony("DeathMonger.GrabMaterialsMod"); public static GrabMaterialsMod Instance; internal static ManualLogSource Log; public ConfigEntry<bool> GrabDeltaGlobal; public ConfigEntry<float> GrabDeltaLedgerTimeout; public ConfigEntry<float> HighlightDuration; public ConfigEntry<float> ContainerRange; public ConfigEntry<float> PanelIdleTimeout; public ConfigEntry<float> PanelFadeDuration; public ConfigEntry<bool> PanelDismissOnMovement; public ConfigEntry<bool> PanelCategoryUnderlines; public ConfigEntry<bool> PanelShowItemIcons; public ConfigEntry<bool> PanelMarkUndiscovered; public ConfigEntry<bool> PanelPauseWhileOpen; public ConfigEntry<float> PanelIconSize; public ConfigEntry<int> PanelScrollRows; public ConfigEntry<MaterialsPanel.InventoryShape> InventoryShape; public ConfigEntry<MaterialsPanel.InventoryStyle> InventoryStyle; public ConfigEntry<bool> ShowDistanceHud; public ConfigEntry<bool> ShowDistanceCoords; public ConfigEntry<float> DistanceHudOffsetX; public ConfigEntry<float> DistanceHudOffsetY; public ConfigEntry<bool> ShowPackHud; public ConfigEntry<KeyboardShortcut> PackHudToggleKey; public ConfigEntry<PackHud.Anchor> PackHudAnchor; public ConfigEntry<float> PackHudOffsetX; public ConfigEntry<float> PackHudOffsetY; public ConfigEntry<bool> PackHudShowBuildPieceKey; public ConfigEntry<bool> PackHudHideUndiscovered; private ButtonConfig GrabSelectedPieceMatsButton; private ConfigEntry<KeyCode> GrabSelectedPieceMatsKeyboardConfig; public GrabPackConfig[] GrabPacks; private FileSystemWatcher _configWatcher; private static readonly MethodInfo KeyCodeToPathMethod = AccessTools.Method(typeof(ZInput), "KeyCodeToPath", new Type[2] { typeof(KeyCode), typeof(bool) }, (Type[])null); internal static float Range => Instance?.ContainerRange?.Value ?? 20f; internal KeyCode GrabSelectedPieceKey => GrabSelectedPieceMatsKeyboardConfig.Value; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; if ((Object)(object)Instance == (Object)null) { Log.LogInfo((object)"GrabMaterialsMod instance created and Awake called for the first time"); Instance = this; } else if ((Object)(object)Instance == (Object)(object)this) { Log.LogWarning((object)"GrabMaterialsMod Awake called an additional time"); } else { Log.LogError((object)"GrabMaterialsMod instance already exists, additional one created, should it be destroyed?"); Instance = this; } harmony.PatchAll(); InitConfig(); SetupConfigWatcher(); InitCommands(); InitButtons(); } private void SetupConfigWatcher() { try { _configWatcher = new FileSystemWatcher(Paths.ConfigPath, Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath)); _configWatcher.Changed += OnConfigFileChanged; _configWatcher.Created += OnConfigFileChanged; _configWatcher.Renamed += OnConfigFileChanged; _configWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _configWatcher.EnableRaisingEvents = true; } catch (Exception ex) { Log.LogWarning((object)("Could not watch config file for changes: " + ex.Message)); } } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return; } try { ((BaseUnityPlugin)this).Config.Reload(); Log.LogInfo((object)"Config file changed on disk; settings reloaded"); } catch (Exception ex) { Log.LogError((object)("Config file changed but could not be reloaded: " + ex.Message)); } } private void InitConfig() { //IL_000b: 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_0039: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Expected O, but got Unknown //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Expected O, but got Unknown //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Expected O, but got Unknown //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Expected O, but got Unknown //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Expected O, but got Unknown //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Expected O, but got Unknown //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Expected O, but got Unknown //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Expected O, but got Unknown //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Expected O, but got Unknown //IL_046f: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Expected O, but got Unknown //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a9: Expected O, but got Unknown //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Expected O, but got Unknown //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Expected O, but got Unknown //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Expected O, but got Unknown //IL_0557: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_05bb: Unknown result type (might be due to invalid IL or missing references) //IL_05ed: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_0648: Unknown result type (might be due to invalid IL or missing references) //IL_067a: Unknown result type (might be due to invalid IL or missing references) //IL_06ac: Unknown result type (might be due to invalid IL or missing references) //IL_06d5: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_075a: Unknown result type (might be due to invalid IL or missing references) new ConfigDescription("Key to grab portal materials", (AcceptableValueBase)null, Array.Empty<object>()); GrabSelectedPieceMatsKeyboardConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Grab Selected Piece", "GrabSelectedPieceMatsKey", (KeyCode)106, new ConfigDescription("Key to grab materials for the currently selectede build piece", (AcceptableValueBase)null, Array.Empty<object>())); HighlightDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Client config", "Highlight Duration", 2f, new ConfigDescription("Duration in seconds to highlight containers when grabbing materials", (AcceptableValueBase)null, Array.Empty<object>())); ContainerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Client config", "Container Range", 20f, new ConfigDescription("How far away (in meters) a container can be and still be used by every command in this mod: grabs, packs, the build-piece hotkey, /inventory, /search and /store. Set it to match your craft-from-containers and auto-store mods so one distance means 'in reach' everywhere.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>())); GrabDeltaGlobal = ((BaseUnityPlugin)this).Config.Bind<bool>("Client config", "Grab Delta (default)", true, new ConfigDescription("If true, all grabs (packs, individual build pieces, /grab <piece>) only grab the shortfall between what you already have and what's needed. Per-pack settings can override this.", (AcceptableValueBase)null, Array.Empty<object>())); GrabDeltaLedgerTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("Client config", "Grab Delta Ledger Timeout (seconds)", 30f, new ConfigDescription("Back-to-back delta grabs share a ledger so the same inventory isn't credited toward two different builds (e.g. /g cart then /g explore won't both 'see' the same 10 wood). After this many seconds without a delta grab, the ledger clears so the next grab considers only what's currently in your inventory. Set to 0 to effectively disable cross-grab tracking.", (AcceptableValueBase)null, Array.Empty<object>())); PanelIdleTimeout = ((BaseUnityPlugin)this).Config.Bind<float>("Panel UI", "Idle Timeout (seconds)", 15f, new ConfigDescription("Seconds the grab-results panel stays fully visible before fading out automatically. 0 means it never fades on its own.", (AcceptableValueBase)null, Array.Empty<object>())); PanelFadeDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Panel UI", "Fade Duration (seconds)", 3f, new ConfigDescription("Seconds the grab-results panel takes to fade out. 0 hides it at once when the idle timeout ends.", (AcceptableValueBase)null, Array.Empty<object>())); PanelDismissOnMovement = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel UI", "Dismiss On Movement", true, new ConfigDescription("Start fading the panel when the player begins moving, attacking, blocking, or jumping. If false, only the idle timeout dismisses the panel.", (AcceptableValueBase)null, Array.Empty<object>())); InventoryStyle = ((BaseUnityPlugin)this).Config.Bind<MaterialsPanel.InventoryStyle>("Panel UI", "Inventory Style", MaterialsPanel.InventoryStyle.List, new ConfigDescription("Display style for the /inventory panel. List = grouped by category, count + name per row (counts right-aligned). Table = flat 3-column table with Category / Item / Count headers.", (AcceptableValueBase)null, Array.Empty<object>())); PanelCategoryUnderlines = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel UI", "Category Underlines", true, new ConfigDescription("In List mode, draw a thin orange line under each category name. Has no effect in Table mode.", (AcceptableValueBase)null, Array.Empty<object>())); InventoryShape = ((BaseUnityPlugin)this).Config.Bind<MaterialsPanel.InventoryShape>("Panel UI", "Inventory Shape", MaterialsPanel.InventoryShape.SlightlyWide, new ConfigDescription("Target shape for the inventory panel in List mode. The panel auto-picks the column count that produces the closest match. MaxHeight = always 1 column. MaxWidth = fan out as many columns as fit on the screen.", (AcceptableValueBase)null, Array.Empty<object>())); PanelShowItemIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel UI", "Show Item Icons", true, new ConfigDescription("Show each item's icon next to its name in the inventory panel.", (AcceptableValueBase)null, Array.Empty<object>())); PanelMarkUndiscovered = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel UI", "Mark Undiscovered Items", true, new ConfigDescription("Mark items in the /inventory panel that this character has never held with a '(new)' tag. Handy in multiplayer, where a shared chest is often full of a friend's crafting you have never handled yourself.", (AcceptableValueBase)null, Array.Empty<object>())); PanelPauseWhileOpen = ((BaseUnityPlugin)this).Config.Bind<bool>("Panel UI", "Pause While Inventory Panel Open", false, new ConfigDescription("Pause the game while the /inventory panel is up, the way the ESC menu does. Toggle it from the button in the panel's top-right corner. This works by itself when playing solo or hosting alone; on a dedicated server it takes the Pause My Server mod. The button shows whether the pause actually took effect.", (AcceptableValueBase)null, Array.Empty<object>())); PanelPauseWhileOpen.SettingChanged += delegate { PanelPause.Refresh(); }; PanelIconSize = ((BaseUnityPlugin)this).Config.Bind<float>("Panel UI", "Icon Size", 24f, new ConfigDescription("Width of the item-icon column in pixels. Icons are square and sized to fit. Beyond ~26 the row stays the same height so icons get visually capped by the row.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(12f, 40f), Array.Empty<object>())); PanelScrollRows = ((BaseUnityPlugin)this).Config.Bind<int>("Panel UI", "Scroll Rows", 4, new ConfigDescription("Rows a panel scrolls per mouse-wheel notch when it is taller than the screen.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); ShowDistanceHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Distance HUD", "Enabled", false, new ConfigDescription("Show a small always-on widget displaying the player's horizontal distance from the world center.", (AcceptableValueBase)null, Array.Empty<object>())); ShowDistanceCoords = ((BaseUnityPlugin)this).Config.Bind<bool>("Distance HUD", "Show Coordinates", false, new ConfigDescription("Also include the player's (X, Z) coordinates in the distance widget.", (AcceptableValueBase)null, Array.Empty<object>())); DistanceHudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Distance HUD", "Offset X (px)", 10f, new ConfigDescription("Horizontal offset from the upper-left corner of the screen.", (AcceptableValueBase)null, Array.Empty<object>())); DistanceHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Distance HUD", "Offset Y (px)", 10f, new ConfigDescription("Vertical offset from the top of the screen.", (AcceptableValueBase)null, Array.Empty<object>())); ShowPackHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Pack HUD", "Show Pack HUD", true, new ConfigDescription("Show a small on-screen list of your grab packs and their hotkeys, like the quick-slot labels in AzuExtendedPlayerInventory. Packs with no items are left out. The toggle key below flips this setting, so the state persists.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Pack HUD", "Toggle Key", new KeyboardShortcut((KeyCode)111, Array.Empty<KeyCode>()), new ConfigDescription("Key to show or hide the pack HUD.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudAnchor = ((BaseUnityPlugin)this).Config.Bind<PackHud.Anchor>("Pack HUD", "Anchor", PackHud.Anchor.BottomLeft, new ConfigDescription("Which corner of the screen the pack HUD sits in. Offsets below are measured from that corner.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Pack HUD", "Offset X (px)", 10f, new ConfigDescription("Horizontal distance from the anchored corner.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Pack HUD", "Offset Y (px)", 300f, new ConfigDescription("Vertical distance from the anchored corner. The default clears the health and stamina bars in the bottom-left.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudShowBuildPieceKey = ((BaseUnityPlugin)this).Config.Bind<bool>("Pack HUD", "Show Build Piece Key", true, new ConfigDescription("Also list the key that grabs materials for the build piece under the cursor.", (AcceptableValueBase)null, Array.Empty<object>())); PackHudHideUndiscovered = ((BaseUnityPlugin)this).Config.Bind<bool>("Pack HUD", "Hide Undiscovered Packs", true, new ConfigDescription("Hide packs that need a material you have never held. A pack reappears once you have picked up every material it needs, so early-game clutter like Karve or Longship packs stays out of the way until nails and the like are in hand.", (AcceptableValueBase)null, Array.Empty<object>())); GrabPacks = new GrabPackConfig[10] { new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 1", "Explore", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), "Workbench,Chest,Portal"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 2", "Karve Explore", new KeyboardShortcut((KeyCode)107, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Workbench,Chest,Portal,Karve"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 3", "Longship Explore", new KeyboardShortcut((KeyCode)107, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Workbench,Chest,Portal,Longship"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 4", "Swamp Explore", new KeyboardShortcut((KeyCode)107, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Workbench,Chest,Portal,Campfire"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 5", "Ashlands Explore", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Workbench,Portal,Campfire:10"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 6", "Ashlands Flametal", new KeyboardShortcut((KeyCode)108, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Workbench,Stone Cutter,Stone Portal,Shield Generator,Bones:10"), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 7", "Grab Pack 7", new KeyboardShortcut((KeyCode)108, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), ""), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 8", "Grab Pack 8", new KeyboardShortcut((KeyCode)108, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), ""), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 9", "Grab Pack 9", new KeyboardShortcut((KeyCode)59, Array.Empty<KeyCode>()), ""), new GrabPackConfig(((BaseUnityPlugin)this).Config, "Grab Pack 10", "Grab Pack 10", new KeyboardShortcut((KeyCode)59, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "") }; GrabPacks[8].Name.SettingChanged += delegate(object sender, EventArgs e) { Log.LogInfo((object)("Grabpack renamed " + sender.ToString() + " " + e.ToString())); }; new ConfigFileWatcher(((BaseUnityPlugin)this).Config, 1000L); } private static void InitCommands() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_006c: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00a5: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_0189: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Expected O, but got Unknown //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Expected O, but got Unknown //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Expected O, but got Unknown object obj = <>c.<>9__44_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { args.GrabItemsFromNearbyContainers(); }; <>c.<>9__44_0 = val; obj = (object)val; } new ConsoleCommand("grab", "[items] - grab items from nearby containers. Use a piece name, a pack name, or 'new' for one of every item you have never held.", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__44_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { args.GrabItemsFromNearbyContainers(); }; <>c.<>9__44_1 = val2; obj2 = (object)val2; } new ConsoleCommand("g", "[items] - grab items from nearby containers. Use a piece name, a pack name, or 'new' for one of every item you have never held.", (ConsoleEvent)obj2, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__44_2; if (obj3 == null) { ConsoleEvent val3 = delegate { ConsoleCommands.GrabMaterialsForSelectedPiece(); }; <>c.<>9__44_2 = val3; obj3 = (object)val3; } new ConsoleCommand("grabselected", "", (ConsoleEvent)obj3, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj4 = <>c.<>9__44_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { args.GrabMaterialsForPiece(); }; <>c.<>9__44_3 = val4; obj4 = (object)val4; } new ConsoleCommand("grabpiece", "grab materials for named build piece, e.g. workbench or portal", (ConsoleEvent)obj4, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj5 = <>c.<>9__44_4; if (obj5 == null) { ConsoleEvent val5 = delegate { ListGrabPacks(); }; <>c.<>9__44_4 = val5; obj5 = (object)val5; } new ConsoleCommand("listpacks", "Lists your configured grab packs.", (ConsoleEvent)obj5, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj6 = <>c.<>9__44_5; if (obj6 == null) { ConsoleEvent val6 = delegate { ConsoleCommands.ResetPendingLedger(); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "Grab delta ledger cleared.", 0, (Sprite)null, false); } }; <>c.<>9__44_5 = val6; obj6 = (object)val6; } new ConsoleCommand("grabreset", "Clear the grab-delta ledger so the next delta grab considers only what's currently in your inventory.", (ConsoleEvent)obj6, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj7 = <>c.<>9__44_6; if (obj7 == null) { ConsoleEvent val7 = delegate(ConsoleEventArgs args) { ListLocalInventory(args); }; <>c.<>9__44_6 = val7; obj7 = (object)val7; } new ConsoleCommand("inventory", "[filter] - counts of items in nearby containers. Filter by item name, by category, with 'new' for items you have never held, or with 'empty' to find and highlight empty containers.", (ConsoleEvent)obj7, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj8 = <>c.<>9__44_7; if (obj8 == null) { ConsoleEvent val8 = delegate(ConsoleEventArgs args) { ListLocalInventory(args); }; <>c.<>9__44_7 = val8; obj8 = (object)val8; } new ConsoleCommand("i", "[filter] - counts of items in nearby containers. Filter by item name, by category, with 'new' for items you have never held, or with 'empty' to find and highlight empty containers.", (ConsoleEvent)obj8, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj9 = <>c.<>9__44_8; if (obj9 == null) { ConsoleEvent val9 = delegate(ConsoleEventArgs args) { SetInventoryStyle(args); }; <>c.<>9__44_8 = val9; obj9 = (object)val9; } new ConsoleCommand("istyle", "[1-2] - cycle inventory display style (1=List, 2=Table)", (ConsoleEvent)obj9, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj10 = <>c.<>9__44_9; if (obj10 == null) { ConsoleEvent val10 = delegate(ConsoleEventArgs args) { FindContainersWithMatchingItems(args); }; <>c.<>9__44_9 = val10; obj10 = (object)val10; } new ConsoleCommand("search", "[search-text] - search for items matching this string in nearby containers", (ConsoleEvent)obj10, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj11 = <>c.<>9__44_10; if (obj11 == null) { ConsoleEvent val11 = delegate(ConsoleEventArgs args) { FindContainersWithMatchingItems(args); }; <>c.<>9__44_10 = val11; obj11 = (object)val11; } new ConsoleCommand("s", "[search-text] - search for items matching this string in nearby containers", (ConsoleEvent)obj11, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj12 = <>c.<>9__44_11; if (obj12 == null) { ConsoleEvent val12 = delegate { StoreItemsInNearbyContainers(); }; <>c.<>9__44_11 = val12; obj12 = (object)val12; } new ConsoleCommand("store", "[items] - stores items randomly nearby containers", (ConsoleEvent)obj12, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private void InitButtons() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) GrabSelectedPieceMatsButton = new ButtonConfig { Name = "GrabSelectedPieceMaterials", Config = GrabSelectedPieceMatsKeyboardConfig }; InputManager.Instance.AddButton("DeathMonger.GrabMaterialsMod", GrabSelectedPieceMatsButton); for (int i = 0; i < GrabPacks.Length; i++) { GrabPackConfig packRef; GrabPackConfig grabPackConfig = (packRef = GrabPacks[i]); int num = i + 1; if (!grabPackConfig.HasName && !grabPackConfig.HasKey) { Log.LogWarning((object)(grabPackConfig.Section + " has no name and no key, so nothing can reach it. Name it in the packs panel, or set '" + grabPackConfig.Section + " Name' or '" + grabPackConfig.Section + " Key' in the config.")); grabPackConfig.Button = null; grabPackConfig.Key.SettingChanged += delegate { NoteKeyChange(packRef); }; continue; } if (!grabPackConfig.HasName) { Log.LogWarning((object)$"{grabPackConfig.Section} has no name. Its key {grabPackConfig.Key.Value} and '/g pack {num}' work, but '/g <name>' cannot reach it. Name it in the packs panel or set '{grabPackConfig.Section} Name' in the config."); } if (!grabPackConfig.HasKey) { Log.LogInfo((object)$"{grabPackConfig.Section} \"{grabPackConfig.Name.Value}\" has no key; '/g {grabPackConfig.Name.Value}' and '/g pack {num}' still work. Set '{grabPackConfig.Section} Key' in the config to add one (takes effect after a restart)."); grabPackConfig.Button = null; grabPackConfig.Key.SettingChanged += delegate { NoteKeyChange(packRef); }; } else { InputManager.Instance.AddButton("DeathMonger.GrabMaterialsMod", grabPackConfig.Button); grabPackConfig.Key.SettingChanged += delegate { //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_001e: Unknown result type (might be due to invalid IL or missing references) ButtonConfig button = packRef.Button; KeyboardShortcut value2 = packRef.Key.Value; RebindButton(button, ((KeyboardShortcut)(ref value2)).MainKey); }; } } Dictionary<string, GrabPackConfig> dictionary = new Dictionary<string, GrabPackConfig>(StringComparer.OrdinalIgnoreCase); GrabPackConfig[] grabPacks = GrabPacks; foreach (GrabPackConfig grabPackConfig2 in grabPacks) { if (grabPackConfig2.HasName) { string text = grabPackConfig2.Name.Value.Trim(); if (dictionary.TryGetValue(text, out var value)) { Log.LogWarning((object)(value.Section + " and " + grabPackConfig2.Section + " are both named \"" + text + "\"; '/g " + text + "' uses " + value.Section + ". Rename one in the packs panel.")); } else { dictionary[text] = grabPackConfig2; } } } } private static void NoteKeyChange(GrabPackConfig pack) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (pack.HasKey) { Log.LogInfo((object)$"{pack.Section} key set to {pack.Key.Value}; it works after the next restart."); } } private static void RebindButton(ButtonConfig button, KeyCode key) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) try { if (button == null || ZInput.instance == null || KeyCodeToPathMethod == null) { return; } ButtonDef buttonDef = ZInput.instance.GetButtonDef(button.Name); if (buttonDef != null) { string text = KeyCodeToPathMethod.Invoke(null, new object[2] { key, false }) as string; if (!string.IsNullOrEmpty(text)) { buttonDef.Rebind(text); Log.LogInfo((object)$"Rebound {button.Name} to {key}"); } } } catch (Exception ex) { Log.LogWarning((object)("Could not rebind " + ((button != null) ? button.Name : null) + ": " + ex.Message)); } } private void InitButton(string name, KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ButtonConfig val = new ButtonConfig { Name = name, Config = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("", name, key, (ConfigDescription)null) }; InputManager.Instance.AddButton("DeathMonger.GrabMaterialsMod", val); } private static bool GuiHasFocus() { if (!Console.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !TextInput.IsVisible() && !StoreGui.IsVisible() && !Minimap.IsOpen() && !PlayerCustomizaton.IsBarberGuiVisible()) { if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.IsChatDialogWindowVisible(); } return false; } return true; } private void Update() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) MaterialsPanel.Tick(); DistanceHud.Tick(); PackHud.Tick(); PanelPause.Refresh(); if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)Chat.instance) || Chat.instance.IsChatDialogWindowVisible()) { return; } if (ZInput.GetButtonDown(GrabSelectedPieceMatsButton.Name)) { ConsoleCommands.GrabMaterialsForSelectedPiece(); } KeyboardShortcut value = PackHudToggleKey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && !GuiHasFocus()) { ShowPackHud.Value = !ShowPackHud.Value; PackHud.Refresh(); } GrabPackConfig[] grabPacks = GrabPacks; foreach (GrabPackConfig grabPackConfig in grabPacks) { if (grabPackConfig.Button != null && ZInput.GetButtonDown(grabPackConfig.Button.Name)) { ConsoleCommands.GrabMaterialsForPack(grabPackConfig); } } } private void OnDestroy() { harmony.UnpatchSelf(); } private static void SetInventoryStyle(ConsoleEventArgs args) { MaterialsPanel.InventoryStyle[] array = (MaterialsPanel.InventoryStyle[])Enum.GetValues(typeof(MaterialsPanel.InventoryStyle)); MaterialsPanel.InventoryStyle inventoryStyle; if (args.Length > 1 && int.TryParse(args[1], out var result) && result >= 1 && result <= array.Length) { inventoryStyle = array[result - 1]; } else { MaterialsPanel.InventoryStyle value = Instance.InventoryStyle.Value; int num = Array.IndexOf(array, value); inventoryStyle = array[(num + 1) % array.Length]; } Instance.InventoryStyle.Value = inventoryStyle; Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, $"Inventory style: {inventoryStyle}", 0, (Sprite)null, false); } } private static string FormatCategoryName(Extensions.ItemCategory cat) { string text = cat.ToString(); StringBuilder stringBuilder = new StringBuilder(text.Length + 4); for (int i = 0; i < text.Length; i++) { if (i > 0 && char.IsUpper(text[i])) { stringBuilder.Append(' '); } stringBuilder.Append(text[i]); } return stringBuilder.ToString(); } private static void ListLocalInventory(ConsoleEventArgs args) { float range = Range; string text = ((args.Length > 1) ? args.ArgsAll.ToLower() : null); Player player = Player.m_localPlayer; bool isNewSearch = text == "new"; if (text == "empty") { ListEmptyContainers(Boxes.GetNearbyContainers(range)); return; } List<Container> nearbyContainers = Boxes.GetNearbyContainers(range); List<Smelter> nearbySmelters = Boxes.GetNearbySmelters(range); Log.LogInfo((object)$"searching {nearbyContainers.Count} containers and {nearbySmelters.Count} processors within {range} meters"); Dictionary<Extensions.ItemCategory, SortedDictionary<string, int>> dictionary = new Dictionary<Extensions.ItemCategory, SortedDictionary<string, int>>(); Dictionary<string, Sprite> dictionary2 = new Dictionary<string, Sprite>(); Dictionary<string, Dictionary<string, int>> dictionary3 = new Dictionary<string, Dictionary<string, int>>(); Dictionary<string, Dictionary<string, int>> dictionary4 = new Dictionary<string, Dictionary<string, int>>(); Extensions.ItemCategory searchCategory = Extensions.ItemCategory.None; bool isCategorySearch = text != null && Enum.TryParse<Extensions.ItemCategory>(text, ignoreCase: true, out searchCategory); foreach (Container item2 in nearbyContainers) { Inventory inventory = item2.GetInventory(); if (inventory == null) { continue; } bool flag = false; foreach (ItemData allItem in inventory.GetAllItems()) { if (Matches(allItem)) { string name = allItem.m_shared.m_name; Extensions.ItemCategory category = allItem.GetCategory(); if (!dictionary.TryGetValue(category, out var value)) { value = (dictionary[category] = new SortedDictionary<string, int>()); } if (value.ContainsKey(name)) { value[name] += allItem.Count(); } else { value[name] = allItem.Count(); } if (!dictionary2.ContainsKey(name) && allItem.m_shared.m_icons != null && allItem.m_shared.m_icons.Length != 0) { dictionary2[name] = allItem.m_shared.m_icons[0]; } if (!flag) { item2.Highlight(); flag = true; } } } } foreach (Smelter item3 in nearbySmelters) { Dictionary<string, int> queuedItems = Processors.GetQueuedItems(item3); if (queuedItems.Count == 0) { continue; } string label = Processors.GetLabel(item3); bool flag2 = false; foreach (KeyValuePair<string, int> item4 in queuedItems) { ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab(item4.Key) : null); if ((Object)(object)val == (Object)null) { continue; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { continue; } ItemData itemData = component.m_itemData; if (Matches(itemData)) { string name2 = itemData.m_shared.m_name; Extensions.ItemCategory category2 = itemData.GetCategory(); if (!dictionary.TryGetValue(category2, out var value2)) { value2 = (dictionary[category2] = new SortedDictionary<string, int>()); } if (value2.ContainsKey(name2)) { value2[name2] += item4.Value; } else { value2[name2] = item4.Value; } if (!dictionary3.TryGetValue(name2, out var value3)) { value3 = (dictionary3[name2] = new Dictionary<string, int>()); } value3.TryGetValue(label, out var value4); value3[label] = value4 + item4.Value; if (!dictionary2.ContainsKey(name2) && itemData.m_shared.m_icons != null && itemData.m_shared.m_icons.Length != 0) { dictionary2[name2] = itemData.m_shared.m_icons[0]; } if (!flag2) { Processors.Highlight(item3); flag2 = true; } } } } List<Piles.Pile> nearby = Piles.GetNearby(range); Log.LogInfo((object)$"and {nearby.Count} stacks or piles"); foreach (Piles.Pile item5 in nearby) { ItemData item = item5.Item; if (item != null && Matches(item)) { string name3 = item.m_shared.m_name; Extensions.ItemCategory category3 = item.GetCategory(); if (!dictionary.TryGetValue(category3, out var value5)) { value5 = (dictionary[category3] = new SortedDictionary<string, int>()); } if (value5.ContainsKey(name3)) { value5[name3] += item5.Amount; } else { value5[name3] = item5.Amount; } if (!dictionary3.TryGetValue(name3, out var value6)) { value6 = (dictionary3[name3] = new Dictionary<string, int>()); } value6.TryGetValue(item5.Kind, out var value7); value6[item5.Kind] = value7 + item5.Amount; if (!dictionary4.TryGetValue(name3, out var value8)) { value8 = (dictionary4[name3] = new Dictionary<string, int>()); } value8.TryGetValue(item5.Kind, out var value9); value8[item5.Kind] = value9 + 1; if (!dictionary2.ContainsKey(name3) && item.m_shared.m_icons != null && item.m_shared.m_icons.Length != 0) { dictionary2[name3] = item.m_shared.m_icons[0]; } Piles.Highlight(item5.Piece); } } if (dictionary.Count == 0) { string text2 = (string.IsNullOrEmpty(text) ? "No items in nearby containers, processors, stacks or piles" : (isNewSearch ? "Nothing here you have not held before" : ("No items match '" + text + "'"))); ((Character)Player.m_localPlayer).Message((MessageType)2, text2, 0, (Sprite)null, false); return; } bool flag3 = (Instance?.PanelMarkUndiscovered?.Value ?? true) && (Object)(object)player != (Object)null && !isNewSearch; List<MaterialsPanel.InventoryGroup> list = new List<MaterialsPanel.InventoryGroup>(); foreach (Extensions.ItemCategory value15 in Enum.GetValues(typeof(Extensions.ItemCategory))) { if (value15 == Extensions.ItemCategory.None || !dictionary.TryGetValue(value15, out var value10)) { continue; } List<MaterialsPanel.InventoryItem> list2 = new List<MaterialsPanel.InventoryItem>(value10.Count); foreach (KeyValuePair<string, int> item6 in value10) { string text3 = Extensions.Localize(item6.Key); bool flag4 = flag3 && !player.IsMaterialKnown(item6.Key); Log.LogInfo((object)string.Format("{0} {1} [{2}]{3}", item6.Value, text3, value15, flag4 ? " (new, never held)" : "")); dictionary2.TryGetValue(item6.Key, out var value11); int num = 0; string inProcessLocation = null; if (dictionary3.TryGetValue(item6.Key, out var value12)) { List<string> list3 = new List<string>(); dictionary4.TryGetValue(item6.Key, out var value13); foreach (KeyValuePair<string, int> item7 in value12) { num += item7.Value; string text4 = item7.Key; if (value13 != null && value13.TryGetValue(text4, out var value14) && value14 > 1) { text4 += "s"; } list3.Add(text4); } inProcessLocation = ((list3.Count == 1) ? list3[0] : (string.Join(", ", list3.GetRange(0, list3.Count - 1)) + " and " + list3[list3.Count - 1])); } list2.Add(new MaterialsPanel.InventoryItem { Name = text3, Count = item6.Value, InProcess = num, InProcessLocation = inProcessLocation, Icon = value11, SharedName = item6.Key, Undiscovered = flag4 }); } list.Add(new MaterialsPanel.InventoryGroup { CategoryName = FormatCategoryName(value15), Items = list2 }); } MaterialsPanel.ShowCategorizedInventory(string.IsNullOrEmpty(text) ? "Inventory" : (isNewSearch ? "New Items" : ("Inventory: " + text)), list, Instance.InventoryStyle.Value); bool Matches(ItemData val2) { string name4 = val2.m_shared.m_name; if (isNewSearch) { if ((Object)(object)player != (Object)null) { return !player.IsMaterialKnown(name4); } return false; } Extensions.ItemCategory category4 = val2.GetCategory(); if (isCategorySearch) { return category4 == searchCategory; } if (text == null) { return true; } string text5 = Extensions.Localize(name4).ToLower(); if (!val2.Name().Contains(text) && !name4.Contains(text) && !text5.Contains(text)) { return category4.ToString().ToLower().Contains(text); } return true; } } private static void ListEmptyContainers(List<Container> nearbyContainers) { Log.LogInfo((object)$"checking {nearbyContainers.Count} nearby containers for empty ones"); SortedDictionary<string, int> sortedDictionary = new SortedDictionary<string, int>(); int num = 0; foreach (Container nearbyContainer in nearbyContainers) { if ((Object)(object)nearbyContainer == (Object)null) { continue; } Inventory inventory = nearbyContainer.GetInventory(); if (inventory != null && inventory.NrOfItems() <= 0) { string text = Extensions.Localize(nearbyContainer.m_name); if (string.IsNullOrEmpty(text)) { text = ((Object)nearbyContainer).name; } if (sortedDictionary.ContainsKey(text)) { sortedDictionary[text]++; } else { sortedDictionary[text] = 1; } num++; nearbyContainer.Highlight(); } } if (num == 0) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "No empty containers nearby", 0, (Sprite)null, false); } return; } List<MaterialsPanel.InventoryItem> list = new List<MaterialsPanel.InventoryItem>(sortedDictionary.Count); foreach (KeyValuePair<string, int> item in sortedDictionary) { Log.LogInfo((object)$"{item.Value} empty {item.Key}"); list.Add(new MaterialsPanel.InventoryItem { Name = item.Key, Count = item.Value }); } List<MaterialsPanel.InventoryGroup> groups = new List<MaterialsPanel.InventoryGroup> { new MaterialsPanel.InventoryGroup { CategoryName = "Empty Containers", Items = list } }; MaterialsPanel.ShowCategorizedInventory("Empty Containers", groups, Instance.InventoryStyle.Value); } internal static string FormatShortcut(KeyboardShortcut shortcut) { //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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { string text = ((object)modifier/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Left")) { text = text.Substring(4); } else if (text.StartsWith("Right")) { text = text.Substring(5); } if (text == "Control") { text = "Ctrl"; } stringBuilder.Append(text).Append(" + "); } stringBuilder.Append(((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString()); return stringBuilder.ToString(); } private static string FormatDelta(GrabPackConfig pack) { bool flag = ConsoleCommands.ResolveDelta(pack.GrabDelta.Value); switch (pack.GrabDelta.Value) { case DeltaSetting.On: return "On"; case DeltaSetting.Off: return "Off"; default: if (!flag) { return "Off (default)"; } return "On (default)"; } } private static void ListGrabPacks() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) Log.LogInfo((object)$"listing {Instance.GrabPacks.Length} configured grab packs"); List<MaterialsPanel.PackRow> list = new List<MaterialsPanel.PackRow>(Instance.GrabPacks.Length); GrabPackConfig[] grabPacks = Instance.GrabPacks; foreach (GrabPackConfig grabPackConfig in grabPacks) { Log.LogInfo((object)$"{grabPackConfig.Name.Value} ({grabPackConfig.Key.Value}): {grabPackConfig.Items.Value}"); GrabPackConfig packRef = grabPackConfig; bool flag = !string.IsNullOrEmpty(grabPackConfig.Items.Value); list.Add(new MaterialsPanel.PackRow { Name = grabPackConfig.Name.Value, Hotkey = FormatShortcut(grabPackConfig.Key.Value), Items = grabPackConfig.Items.Value, Delta = FormatDelta(grabPackConfig), OnClick = (flag ? ((Action)delegate { ConsoleCommands.GrabMaterialsForPack(packRef); }) : null), OnEdit = delegate { OpenPackEditor(packRef); } }); } MaterialsPanel.ShowPacks("Grab Packs", list); } private static void OpenPackEditor(GrabPackConfig pack) { MaterialsPanel.ShowPackEditor("Edit: " + pack.Name.Value, pack.Name.Value, pack.Items.Value, pack.GrabDelta.Value, delegate(string newName, string newItems, DeltaSetting newDelta) { if (string.IsNullOrWhiteSpace(newName)) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "A pack needs a name; keeping \"" + pack.Name.Value + "\"", 0, (Sprite)null, false); } } else { pack.Name.Value = newName.Trim(); } pack.Items.Value = newItems; pack.GrabDelta.Value = newDelta; ListGrabPacks(); }, delegate { ListGrabPacks(); }); } private static void FindContainersWithMatchingItems(ConsoleEventArgs args) { if (args.Length <= 1) { string text = "Please specify the text you want to search for in nearby containers"; ((Component)Chat.instance).SendMessage(text); Log.LogInfo((object)text); return; } float range = Range; string text2 = args[1]; List<Container> nearbyContainers = Boxes.GetNearbyContainers(range); Log.LogInfo((object)$"searching for {text2} in {nearbyContainers.Count} containers within {range} meters"); foreach (Container item in nearbyContainers) { Inventory inventory = item.GetInventory(); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.Name().Contains(text2)) { Log.LogInfo((object)("it contains " + text2 + "!")); item.Highlight(); } } if (inventory.ContainsItemByName(text2)) { Log.LogInfo((object)("it contains " + text2 + "!")); item.Highlight(); } } } private static void StoreItemsInNearbyContainers() { float radius = Range; List<Container> openableContainers = Boxes.GetOpenableContainers(radius); if (openableContainers.Count == 0) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "No container you can open within range", 0, (Sprite)null, false); } } else { ContainerAccess.Acquire(openableContainers, delegate(List<Container> owned) { StoreItemsInContainers(owned, radius); }); } } private static void StoreItemsInContainers(List<Container> nearbyContainers, float radius) { if (nearbyContainers.Count == 0) { Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "No container would hand itself over", 0, (Sprite)null, false); } return; } Player localPlayer2 = Player.m_localPlayer; Inventory inventory = ((Humanoid)localPlayer2).GetInventory(); List<ItemData> list = new List<ItemData>(); ((Character)localPlayer2).Message((MessageType)2, $"Storing items in {nearbyContainers.Count} containers within {radius} meters", 0, (Sprite)null, false); for (int i = 1; i < inventory.GetHeight(); i++) { for (int j = 0; j < inventory.GetWidth(); j++) { ItemData itemAt = inventory.GetItemAt(j, i); if (itemAt != null) { list.Add(itemAt); } } } Log.LogInfo((object)$"storing {list.Count()} items in {nearbyContainers.Count} containers within {radius} meters"); int num = 0; while (list.Count > 0) { nearbyContainers[num].StoreItemInContainer(list[0]); num++; if (num == nearbyContainers.Count) { num = 0; } list.RemoveAt(0); } } } } namespace GrabMaterials { internal class Boxes { internal static readonly List<Container> Containers = new List<Container>(); private static readonly List<Container> ContainersToAdd = new List<Container>(); private static readonly List<Container> ContainersToRemove = new List<Container>(); internal static readonly List<Smelter> Smelters = new List<Smelter>(); private static readonly List<Smelter> SmeltersToAdd = new List<Smelter>(); private static readonly List<Smelter> SmeltersToRemove = new List<Smelter>(); internal static void AddContainer(Container container) { if (!Containers.Contains(container)) { ContainersToAdd.Add(container); Logger.LogDebug((object)$"Added container {((Object)container).name} ({((object)container).GetType()} {((Object)container).GetInstanceID()}) to list"); } UpdateContainers(); } internal static void RemoveContainer(Container container) { if (Containers.Contains(container)) { ContainersToRemove.Add(container); Logger.LogDebug((object)$"Removed container {((Object)container).name} ({((object)container).GetType()} {((Object)container).GetInstanceID()}) from list"); } UpdateContainers(); } internal static void UpdateContainers() { foreach (Container item in ContainersToAdd) { Containers.Add(item); } ContainersToAdd.Clear(); foreach (Container item2 in ContainersToRemove) { Containers.Remove(item2); } ContainersToRemove.Clear(); } internal static void ConditionallyAddContainer(Container container, string trigger) { if (container.GetInventory() != null) { Game.instance.GetPlayerProfile().GetPlayerID(); AddContainer(container); } } internal static void AddSmelter(Smelter smelter) { if (!Smelters.Contains(smelter)) { SmeltersToAdd.Add(smelter); Logger.LogDebug((object)$"Added smelter {((Object)smelter).name} ({((object)smelter).GetType()} {((Object)smelter).GetInstanceID()}) to list"); } UpdateSmelters(); } internal static void RemoveSmelter(Smelter smelter) { if (Smelters.Contains(smelter)) { SmeltersToRemove.Add(smelter); Logger.LogDebug((object)$"Removed smelter {((Object)smelter).name} ({((object)smelter).GetType()} {((Object)smelter).GetInstanceID()}) from list"); } UpdateSmelters(); } internal static void UpdateSmelters() { foreach (Smelter item in SmeltersToAdd) { Smelters.Add(item); } SmeltersToAdd.Clear(); foreach (Smelter item2 in SmeltersToRemove) { Smelters.Remove(item2); } SmeltersToRemove.Clear(); } internal static void ConditionallyAddSmelter(Smelter smelter) { if (!((Object)(object)smelter == (Object)null)) { AddSmelter(smelter); } } internal static List<Smelter> GetNearbySmelters(float radius) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) List<Smelter> list = new List<Smelter>(); if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return list; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; foreach (Smelter smelter in Smelters) { if ((Object)(object)smelter == (Object)null || (Object)(object)((Component)smelter).transform == (Object)null) { SmeltersToRemove.Add(smelter); } else if (Vector3.Distance(position, ((Component)smelter).transform.position) < radius) { list.Add(smelter); } } UpdateSmelters(); return list; } internal static List<Container> GetOpenableContainers(float radius) { List<Container> nearbyContainers = GetNearbyContainers(radius); List<Container> list = new List<Container>(nearbyContainers.Count); Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (Container item in nearbyContainers) { if (ContainerAccess.CanOpen(item, out var reason)) { list.Add(item); continue; } dictionary.TryGetValue(reason, out var value); dictionary[reason] = value + 1; } foreach (KeyValuePair<string, int> item2 in dictionary) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"skipping {item2.Value} {item2.Key} container(s) within {radius} m"); } return list; } internal static List<Container> GetNearbyContainers(float radius) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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) List<Container> list = new List<Container>(); if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return list; } Vector3 position = ((Component)Player.m_localPlayer).transform.position; global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"checking distance of {Containers.Count} containers"); foreach (Container container in Containers) { if ((Object)(object)container == (Object)null) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogWarning((object)"Found null container in list"); ContainersToRemove.Add(container); } else if ((Object)(object)((Component)container).transform == (Object)null) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogWarning((object)("Found container " + ((Object)container).name + " with null transform in list")); ContainersToRemove.Add(container); } else if (Vector3.Distance(position, ((Component)container).transform.position) < radius) { list.Add(container); } } UpdateContainers(); return list; } } internal static class ConsoleCommands { private struct ItemToGrab { public string Name; public int Count; public string FullName => "$item_" + Name; public ItemToGrab(string name, int count) { Name = CanonicalItemName(name.Replace("$item_", "")); Count = count; } } private static Dictionary<string, Piece> pieceLookup = new Dictionary<string, Piece>(); private static Dictionary<string, GameObject> itemLookup = new Dictionary<string, GameObject>(); private static readonly Dictionary<string, int> _pendingByName = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); private static float _lastGrabTime; private static string _lastFailedRequestKey; private static float _lastFailedRequestTime; private const float OverrideTimeoutSeconds = 30f; private static FieldRef<Hud, List<PieceIconData>> _pieceIconsAccessor; private static Dictionary<string, string> sharedNameLookup = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); internal static bool GlobalDelta => global::GrabMaterialsMod.GrabMaterialsMod.Instance?.GrabDeltaGlobal?.Value ?? true; private static float LedgerTimeoutSeconds => global::GrabMaterialsMod.GrabMaterialsMod.Instance?.GrabDeltaLedgerTimeout?.Value ?? 30f; internal static bool ResolveDelta(global::GrabMaterialsMod.GrabMaterialsMod.DeltaSetting setting) { return setting switch { global::GrabMaterialsMod.GrabMaterialsMod.DeltaSetting.On => true, global::GrabMaterialsMod.GrabMaterialsMod.DeltaSetting.Off => false, _ => GlobalDelta, }; } internal static void ResetPendingLedger() { _pendingByName.Clear(); _lastGrabTime = 0f; } private static void MaybeExpirePendingLedger() { if (_pendingByName.Count != 0 && Time.time - _lastGrabTime > LedgerTimeoutSeconds) { _pendingByName.Clear(); } } private static int GetPending(string name) { if (!_pendingByName.TryGetValue(name, out var value)) { return 0; } return value; } private static void AddPending(string name, int amount) { if (amount > 0) { _pendingByName[name] = GetPending(name) + amount; } } internal static void ClearOverrideState() { _lastFailedRequestKey = null; _lastFailedRequestTime = 0f; } private static string ComputeRequestKey(string requestLabel, List<ItemToGrab> aggregated) { if (!string.IsNullOrEmpty(requestLabel)) { return "label:" + requestLabel.ToLowerInvariant(); } StringBuilder stringBuilder = new StringBuilder("items:"); foreach (ItemToGrab item in aggregated) { stringBuilder.Append(item.Name.ToLowerInvariant()).Append(':').Append(item.Count) .Append(','); } return stringBuilder.ToString(); } private static bool IsOverrideRequest(string key) { if (_lastFailedRequestKey != null && _lastFailedRequestKey == key) { return Time.time - _lastFailedRequestTime <= 30f; } return false; } public static void GrabMaterialsForPiece(this ConsoleEventArgs args) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("GrabMaterialsForPiece(" + args.FullLine + ")")); if (args.Length <= 1) { string text = "usage: /grabpiece <name>, e.g. /grab workbench"; ((Component)Chat.instance).SendMessage(text); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)text); } else { string text2 = args[1]; global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("name of piece to grab materials for: " + text2)); GrabMaterialsForPiece(text2); } } public static void GrabMaterialsForPack(global::GrabMaterialsMod.GrabMaterialsMod.GrabPackConfig grabPack) { GrabMaterialsForPack(grabPack.Name.Value, grabPack.Items.Value, ResolveDelta(grabPack.GrabDelta.Value)); } public static void GrabMaterialsForPack(string packName, string itemsString, bool grabDelta = false) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("GrabMaterialsForPack(" + packName + ", " + itemsString + ")")); List<ItemToGrab> list = new List<ItemToGrab>(); string[] array = itemsString.Replace(" ", "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length > 2) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogError((object)("Invalid format for " + packName + " item list: was " + itemsString + ", expected 'item[:quantity],item[:quantity],...'")); return; } string text = array2[0]; int result = 1; if (array2.Length == 2 && !int.TryParse(array2[1], out result)) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogError((object)("Invalid format for " + packName + " item list: was " + itemsString + ", expected 'item[:quantity],item[:quantity],...'")); return; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"grabbing {result} {text}"); foreach (ItemToGrab item in GetItemsToGrab(text, result)) { list.Add(item); } } GrabItemsFromNearbyContainers(list, global::GrabMaterialsMod.GrabMaterialsMod.Range, packName, grabDelta); } public static void GrabUndiscoveredItems() { float range = global::GrabMaterialsMod.GrabMaterialsMod.Range; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } HashSet<string> hashSet = new HashSet<string>(); List<ItemToGrab> list = new List<ItemToGrab>(); foreach (Container openableContainer in Boxes.GetOpenableContainers(range)) { Inventory inventory = openableContainer.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { string name = allItem.m_shared.m_name; if (!localPlayer.IsMaterialKnown(name) && hashSet.Add(name)) { list.Add(new ItemToGrab(allItem.Name(), 1)); } } } if (list.Count == 0) { ((Character)localPlayer).Message((MessageType)2, "Nothing here you have not held before", 0, (Sprite)null, false); return; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"grabbing one each of {list.Count} never-held items"); GrabItemsFromNearbyContainers(list, range, "New Items"); } public static void GrabItemsFromNearbyContainers(this ConsoleEventArgs args) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"GrabItemsFromNearbyContainers('{args.FullLine})' args.Length={args.Length}"); if (args.Length > 1) { if (args[1] == "pack") { int num = int.Parse(args[2]) - 1; GrabMaterialsForPack(global::GrabMaterialsMod.GrabMaterialsMod.Instance.GrabPacks[num]); return; } if (args.Length == 2 && string.Equals(args[1], "new", StringComparison.OrdinalIgnoreCase)) { GrabUndiscoveredItems(); return; } global::GrabMaterialsMod.GrabMaterialsMod.GrabPackConfig[] grabPacks = global::GrabMaterialsMod.GrabMaterialsMod.Instance.GrabPacks; foreach (global::GrabMaterialsMod.GrabMaterialsMod.GrabPackConfig grabPackConfig in grabPacks) { string argsAll = args.ArgsAll; global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("Checking pack " + grabPackConfig.Name.Value + " against args.ArgsAll='" + argsAll + "'")); if (grabPackConfig.Name.Value == args.ArgsAll) { GrabMaterialsForPack(grabPackConfig); return; } } int num2 = args.Length - 1; int result = 0; int num3 = ((!int.TryParse(args[1], out result)) ? 1 : 2); int num4 = num2; if (result == 0) { num4 = (int.TryParse(args[num2], out result) ? (num2 - 1) : num2); if (result == 0) { result = 1; } } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"count={result}, n={num2}, nameStartingArg={num3}, nameEndingArg={num4}"); StringBuilder stringBuilder = new StringBuilder(); for (int j = num3; j <= num4; j++) { if (stringBuilder.Length > 0) { stringBuilder.Append(" "); } stringBuilder.Append(args[j]); } string text = stringBuilder.ToString(); if (text != "") { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"grabbing {result} '{text}'"); GrabItemsFromNearbyContainers(text, result); return; } } string text2 = "usage: /grab <all | name> [count], e.g. /grab 10 wood"; ((Component)Chat.instance).SendMessage(text2); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)text2); } public static Requirement[] GetPieceRequirements(string pieceName) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("GetPieceRequirements(" + pieceName + ")")); if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogWarning((object)"Cannot look for prefab: ZNetScene.instance is null"); return null; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)"looking for prefab..."); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"ZNetScene.instance has {ZNetScene.instance.m_prefabs.Count} prefabs"); GameObject val = ZNetScene.instance.m_prefabs.Find((GameObject _prefab) => ((Object)_prefab).name == pieceName); if ((Object)(object)val == (Object)null) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogError((object)("No prefab found for " + pieceName)); return null; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("Prefab found: " + ((Object)val).name + " " + ((Object)val.gameObject).name + " " + val.gameObject.tag + " " + val.gameObject.GetComponent<Piece>().m_name)); return val.gameObject.GetComponent<Piece>().m_resources; } private static void GrabMaterialsForPiece(string pieceName) { Requirement[] pieceRequirements = GetPieceRequirements(pieceName); if (pieceRequirements != null) { List<ItemToGrab> list = new List<ItemToGrab>(); Requirement[] array = pieceRequirements; foreach (Requirement val in array) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"Grabbing for {pieceName}: {val.m_amount} {val.m_resItem.m_itemData.m_shared.m_name}"); list.Add(new ItemToGrab(val.m_resItem.m_itemData.m_shared.m_name, val.m_amount)); } GrabItemsFromNearbyContainers(list, global::GrabMaterialsMod.GrabMaterialsMod.Range, pieceName, GlobalDelta); } } private static void GrabItemsFromNearbyContainers(List<ItemToGrab> itemsToGrab, float radius, string requestLabel = null, bool grabDelta = false) { List<Container> list = new List<Container>(); foreach (Container openableContainer in Boxes.GetOpenableContainers(radius)) { Inventory inventory = openableContainer.GetInventory(); if (inventory != null && inventory.GetAllItems().Any((ItemData item) => itemsToGrab.Any((ItemToGrab want) => item.isMatch(want.Name)))) { list.Add(openableContainer); } } ContainerAccess.Acquire(list, delegate(List<Container> owned) { GrabItemsFromContainers(itemsToGrab, owned, requestLabel, grabDelta); }); } private static void GrabItemsFromContainers(List<ItemToGrab> itemsToGrab, List<Container> nearbyContainers, string requestLabel, bool grabDelta) { Player localPlayer = Player.m_localPlayer; List<ItemToGrab> list = new List<ItemToGrab>(); foreach (ItemToGrab item in itemsToGrab) { int num = list.FindIndex((ItemToGrab a) => string.Equals(a.Name, item.Name, StringComparison.OrdinalIgnoreCase)); if (num >= 0) { ItemToGrab value = list[num]; value.Count += item.Count; list[num] = value; } else { list.Add(item); } } if (grabDelta) { MaybeExpirePendingLedger(); } int[] array = new int[list.Count]; int[] array2 = new int[list.Count]; for (int num2 = 0; num2 < list.Count; num2++) { if (grabDelta && (Object)(object)localPlayer != (Object)null) { Inventory inventory = ((Humanoid)localPlayer).GetInventory(); if (inventory != null) { foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.isMatch(list[num2].Name)) { array[num2] += allItem.Count(); } } } int pending = GetPending(list[num2].Name); if (pending > 0) { array[num2] = Math.Max(0, array[num2] - pending); } } array2[num2] = Math.Max(0, list[num2].Count - array[num2]); } bool flag = true; for (int num3 = 0; num3 < list.Count; num3++) { if (array2[num3] > 0) { flag = false; break; } } int[] array3 = new int[list.Count]; foreach (Container nearbyContainer in nearbyContainers) { Inventory inventory2 = nearbyContainer.GetInventory(); if (inventory2 == null) { continue; } foreach (ItemData allItem2 in inventory2.GetAllItems()) { for (int num4 = 0; num4 < list.Count; num4++) { if (array2[num4] != 0 && allItem2.isMatch(list[num4].Name)) { array3[num4] += allItem2.Count(); break; } } } } bool flag2 = false; for (int num5 = 0; num5 < list.Count; num5++) { if (array2[num5] > 0 && array3[num5] < array2[num5]) { flag2 = true; break; } } string text = ComputeRequestKey(requestLabel, list); bool flag3 = flag2 && IsOverrideRequest(text); if (flag2 && !flag3) { List<MaterialsPanel.ItemStatus> list2 = new List<MaterialsPanel.ItemStatus>(list.Count); List<string> list3 = new List<string>(); for (int num6 = 0; num6 < list.Count; num6++) { list2.Add(new MaterialsPanel.ItemStatus { Name = LocalizeItemName(list[num6]), Needed = list[num6].Count, Had = array[num6], Available = array3[num6] }); if (array2[num6] > array3[num6]) { list3.Add($"{array2[num6] - array3[num6]} of {list[num6].Count} {list[num6].Name}"); } } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("Cannot grab" + (string.IsNullOrEmpty(requestLabel) ? "" : (" for " + requestLabel)) + " - missing: " + string.Join(", ", list3))); MaterialsPanel.Show(string.IsNullOrEmpty(requestLabel) ? "Missing materials — run again to grab what's available" : ("Missing materials for " + requestLabel + " — run again to grab what's available"), list2); _lastFailedRequestKey = text; _lastFailedRequestTime = Time.time; if (grabDelta) { _lastGrabTime = Time.time; } return; } List<MaterialsPanel.ItemStatus> list4 = new List<MaterialsPanel.ItemStatus>(list.Count); for (int num7 = 0; num7 < list.Count; num7++) { ItemToGrab item2 = list[num7]; int num8 = array2[num7]; if (num8 > 0) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"grabbing {num8} {item2.Name} from {nearbyContainers.Count} containers"); for (int num9 = 0; num9 < nearbyContainers.Count; num9++) { if (num8 <= 0) { break; } int num10 = nearbyContainers[num9].GrabItemFromContainer(item2.Name, num8); num8 -= num10; } } int num11 = array2[num7] - num8; if (grabDelta) { AddPending(item2.Name, num11); } list4.Add(new MaterialsPanel.ItemStatus { Name = LocalizeItemName(item2), Needed = item2.Count, Had = array[num7], Available = num11 }); } if (grabDelta) { _lastGrabTime = Time.time; } ClearOverrideState(); string text2; if (!flag) { text2 = ((!flag3) ? (string.IsNullOrEmpty(requestLabel) ? "Grabbed materials" : ("Grabbed materials for " + requestLabel)) : (string.IsNullOrEmpty(requestLabel) ? "Partial grab" : ("Partial grab for " + requestLabel))); } else { text2 = (string.IsNullOrEmpty(requestLabel) ? "Already have everything" : ("Already have everything for " + requestLabel)); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)text2); } MaterialsPanel.Show(text2, list4); } private static string LocalizeItemName(ItemToGrab item) { string text = Extensions.Localize(item.FullName); if (!string.IsNullOrEmpty(text) && !(text == item.FullName) && !text.StartsWith("[")) { return text; } return item.Name; } private static string LocalizePieceName(Piece piece) { if ((Object)(object)piece == (Object)null) { return null; } if (!piece.m_name.StartsWith("$")) { return piece.m_name; } try { string text = Extensions.Localize(piece.m_name); return (string.IsNullOrEmpty(text) || text == piece.m_name) ? piece.m_name : text; } catch { return piece.m_name; } } public static void GrabMaterialsForSelectedPiece() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Piece val = GetHoveredBuildPiece() ?? localPlayer.GetSelectedPiece(); if (!Object.op_Implicit((Object)(object)val)) { string text = "No build piece selected or hovered"; global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)text); ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } else { GrabMaterialsForPiece(val); } } } public static void HighlightContainersHolding(string sharedName) { if (string.IsNullOrEmpty(sharedName)) { return; } foreach (Piles.Pile item in Piles.GetNearby(global::GrabMaterialsMod.GrabMaterialsMod.Range)) { if (item.Item?.m_shared?.m_name == sharedName) { Piles.Highlight(item.Piece); } } foreach (Container nearbyContainer in Boxes.GetNearbyContainers(global::GrabMaterialsMod.GrabMaterialsMod.Range)) { Inventory inventory = nearbyContainer.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared.m_name == sharedName) { nearbyContainer.Highlight(); break; } } } } public static void HighlightContainersHoldingAny(ICollection<string> sharedNames) { if (sharedNames == null || sharedNames.Count == 0) { return; } HashSet<string> hashSet = (sharedNames as HashSet<string>) ?? new HashSet<string>(sharedNames); foreach (Piles.Pile item in Piles.GetNearby(global::GrabMaterialsMod.GrabMaterialsMod.Range)) { if (item.Item?.m_shared?.m_name != null && hashSet.Contains(item.Item.m_shared.m_name)) { Piles.Highlight(item.Piece); } } foreach (Container nearbyContainer in Boxes.GetNearbyContainers(global::GrabMaterialsMod.GrabMaterialsMod.Range)) { Inventory inventory = nearbyContainer.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (hashSet.Contains(allItem.m_shared.m_name)) { nearbyContainer.Highlight(); break; } } } } public static Piece GetHoveredBuildPiece() { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Hud instance = Hud.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null) { return null; } if (_pieceIconsAccessor == null) { try { _pieceIconsAccessor = AccessTools.FieldRefAccess<Hud, List<PieceIconData>>("m_pieceIcons"); } catch (Exception ex) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogWarning((object)("GrabMaterials: cannot reflect Hud.m_pieceIcons - " + ex.Message)); return null; } } List<PieceIconData> list = _pieceIconsAccessor.Invoke(instance); if (list == null) { return null; } foreach (PieceIconData item in list) { if (item == null) { continue; } Image icon = item.m_icon; if ((Object)(object)icon == (Object)null || !((Component)icon).gameObject.activeInHierarchy || !RectTransformUtility.RectangleContainsScreenPoint(((Graphic)icon).rectTransform, Vector2.op_Implicit(Input.mousePosition))) { continue; } Sprite sprite = icon.sprite; if ((Object)(object)sprite == (Object)null) { return null; } List<Piece> buildPieces = localPlayer.GetBuildPieces(); if (buildPieces == null) { return null; } foreach (Piece item2 in buildPieces) { if ((Object)(object)item2 != (Object)null && (Object)(object)item2.m_icon == (Object)(object)sprite) { return item2; } } return null; } return null; } public static void GrabMaterialsForPiece(Piece piece) { Requirement[] resources = piece.m_resources; global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"grabbing materials for selected piece {((Object)piece).name} - requires {resources.Count()} resources"); if (resources != null) { List<ItemToGrab> list = new List<ItemToGrab>(); Requirement[] array = resources; foreach (Requirement val in array) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"{val.m_amount} {val.m_resItem.m_itemData.Name()}"); list.Add(new ItemToGrab(val.m_resItem.m_itemData.Name(), val.m_amount)); } GrabItemsFromNearbyContainers(list, global::GrabMaterialsMod.GrabMaterialsMod.Range, LocalizePieceName(piece), GlobalDelta); } } private static void BuildPieceLookUp() { if ((Object)(object)ObjectDB.instance == (Object)null) { return; } if (!Object.op_Implicit((Object)(object)ZNetScene.instance)) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogWarning((object)"Cannot index: ZNetScene.instance is null"); return; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)"building lookup table for all build pieces"); Piece val = default(Piece); foreach (GameObject prefab in ZNetScene.instance.m_prefabs) { if (prefab.TryGetComponent<Piece>(ref val) && !StringExtensions.ContainsAny(((Object)prefab).name, new string[2] { "loot_chest", "TreasureChest" })) { string text = ""; try { text = ((!val.m_name.StartsWith("$")) ? val.m_name : Extensions.Localize(val.m_name)); } catch (Exception ex) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogError((object)("Error translating piece name " + val.m_name + ": " + ex.Message)); text = val.m_name; } pieceLookup[text.ToLowerInvariant()] = val; } } } private static void BuildItemLookUp() { if ((Object)(object)ObjectDB.instance == (Object)null) { return; } Logger.LogInfo((object)"Building item lookup..."); foreach (GameObject item in ObjectDB.instance.m_items) { if (!((Object)(object)item == (Object)null)) { string name = ((Object)item).name; itemLookup[name] = item; } } Logger.LogInfo((object)$"Built a lookup table with {itemLookup.Count} items."); } private static void BuildSharedNameLookup() { if ((Object)(object)ObjectDB.instance == (Object)null) { return; } foreach (GameObject item in ObjectDB.instance.m_items) { string text = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_name; if (string.IsNullOrEmpty(text) || !text.StartsWith("$item_")) { continue; } string key = Extensions.TokenName(text); if (!sharedNameLookup.ContainsKey(key)) { sharedNameLookup[key] = text; } string text2 = Extensions.Localize(text); if (!string.IsNullOrEmpty(text2) && text2 != text && !text2.StartsWith("[")) { if (!sharedNameLookup.ContainsKey(text2)) { sharedNameLookup[text2] = text; } string key2 = text2.Replace(" ", ""); if (!sharedNameLookup.ContainsKey(key2)) { sharedNameLookup[key2] = text; } } } } private static string CanonicalItemName(string name) { if (string.IsNullOrEmpty(name)) { return name; } if (sharedNameLookup.Count == 0) { BuildSharedNameLookup(); } if (sharedNameLookup.TryGetValue(name, out var value)) { return Extensions.TokenName(value); } string text = name.Replace(" ", ""); if (text != name && sharedNameLookup.TryGetValue(text, out value)) { return Extensions.TokenName(value); } return name; } private static bool TryGetPiece(string name, out Piece piece) { if (pieceLookup.Count == 0) { BuildPieceLookUp(); } if (!pieceLookup.TryGetValue(name.ToLowerInvariant(), out piece)) { return false; } if ((Object)(object)((Component)piece).GetComponent<Plant>() == (Object)null) { return true; } if (sharedNameLookup.Count == 0) { BuildSharedNameLookup(); } if (!sharedNameLookup.ContainsKey(name.Replace("$item_", ""))) { return true; } piece = null; return false; } internal static bool AreAllPackMaterialsKnown(string itemsString, Player player) { if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(itemsString)) { return true; } if ((Object)(object)ObjectDB.instance == (Object)null || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return true; } if (sharedNameLookup.Count == 0) { BuildSharedNameLookup(); } if (pieceLookup.Count == 0) { BuildPieceLookUp(); } string[] array = itemsString.Replace(" ", "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Split(new char[1] { ':' })[0]; string value; if (TryGetPiece(text, out var piece)) { if (piece.m_resources == null) { continue; } Requirement[] resources = piece.m_resources; for (int j = 0; j < resources.Length; j++) { string text2 = resources[j].m_resItem?.m_itemData?.m_shared?.m_name; if (!string.IsNullOrEmpty(text2) && !player.IsMaterialKnown(text2)) { return false; } } } else if (sharedNameLookup.TryGetValue(text.Replace("$item_", ""), out value) && !player.IsMaterialKnown(value)) { return false; } } return true; } private static List<ItemToGrab> GetItemsToGrab(string name, int count = 1) { List<ItemToGrab> list = new List<ItemToGrab>(); if (pieceLookup.Count == 0) { BuildPieceLookUp(); } if (itemLookup.Count == 0) { BuildItemLookUp(); } if (TryGetPiece(name, out var piece)) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("Found piece " + name + " in lookup table, grabbing materials for it")); Requirement[] resources = piece.m_resources; if (resources != null) { Requirement[] array = resources; foreach (Requirement val in array) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"{val.m_amount} {val.m_resItem.m_itemData.Name()}"); list.Add(new ItemToGrab(val.m_resItem.m_itemData.Name(), val.m_amount * count)); } } } else { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)("No piece found for " + name + ", looking for material by this name instead")); list.Add(new ItemToGrab(name, count)); } return list; } public static void GrabItemsFromNearbyContainers(string name, int count = 1) { float range = global::GrabMaterialsMod.GrabMaterialsMod.Range; List<ItemToGrab> itemsToGrab = GetItemsToGrab(name, count); Piece piece; bool flag = TryGetPiece(name, out piece); string requestLabel = (flag ? name : null); GrabItemsFromNearbyContainers(itemsToGrab, range, requestLabel, flag && GlobalDelta); } } internal static class ContainerAccess { private const float GrantTimeout = 0.75f; internal static readonly Dictionary<Container, bool?> Requests = new Dictionary<Container, bool?>(); internal static ZNetView NetView(Container container) { if ((Object)(object)container == (Object)null) { return null; } if (!((Object)(object)container.m_rootObjectOverride != (Object)null)) { return ((Component)container).GetComponent<ZNetView>(); } return container.m_rootObjectOverride; } internal static bool CanOpen(Container container, out string reason) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Invalid comparison between Unknown and I4 reason = null; if ((Object)(object)container == (Object)null) { return false; } if (container.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { reason = "warded"; return false; } PrivacySetting privacy = container.m_privacy; if ((int)privacy != 0) { if ((int)privacy != 2) { reason = "group"; return false; } } else { Piece component = ((Component)container).GetComponent<Piece>(); long playerID = Game.instance.GetPlayerProfile().GetPlayerID(); if ((Object)(object)component == (Object)null || component.GetCreator() != playerID) { reason = "personal"; return false; } } ZNetView val = NetView(container); if ((Object)(object)val != (Object)null && val.IsValid() && (val.IsOwner() ? container.IsInUse() : (val.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 1))) { reason = "in use"; return false; } return true; } internal static bool EnsureOwned(Container container) { ZNetView val = NetView(container); if ((Object)(object)val == (Object)null || !val.IsValid()) { return true; } if (!val.IsOwner() && !val.HasOwner()) { val.ClaimOwnership(); } return val.IsOwner(); } internal static void Acquire(List<Container> containers, Action<List<Container>> onReady) { List<Container> list = new List<Container>(); List<Container> list2 = new List<Container>(); long playerID = Game.instance.GetPlayerProfile().GetPlayerID(); foreach (Container container in containers) { if ((Object)(object)container == (Object)null) { continue; } ZNetView val = NetView(container); if ((Object)(object)val == (Object)null || !val.IsValid() || val.IsOwner()) { list.Add(container); } else if (!val.HasOwner()) { val.ClaimOwnership(); if (val.IsOwner()) { list.Add(container); } } else if (!Requests.ContainsKey(container)) { Requests[container] = null; val.InvokeRPC("RPC_RequestOpen", new object[1] { playerID }); list2.Add(container); } } if (list2.Count == 0) { onReady(list); return; } global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"asking the owners of {list2.Count} container(s) to hand them over"); ((MonoBehaviour)global::GrabMaterialsMod.GrabMaterialsMod.Instance).StartCoroutine(AwaitGrants(list, list2, onReady)); } private static bool Settled(Container container) { if ((Object)(object)container == (Object)null) { return true; } if (!Requests.TryGetValue(container, out var value) || !value.HasValue) { return false; } if (value.Value) { return NetView(container).IsOwner(); } return true; } private static IEnumerator AwaitGrants(List<Container> owned, List<Container> pending, Action<List<Container>> onReady) { float deadline = Time.unscaledTime + 0.75f; while (Time.unscaledTime < deadline) { bool flag = true; foreach (Container item in pending) { if (!Settled(item)) { flag = false; break; } } if (flag) { break; } yield return null; } foreach (Container item2 in pending) { Requests.TryGetValue(item2, out var value); Requests.Remove(item2); if (!((Object)(object)item2 == (Object)null)) { if (value == true && NetView(item2).IsOwner()) { owned.Add(item2); continue; } string arg = ((!value.HasValue) ? "its owner did not answer" : ((value == false) ? "its owner refused (in use or not yours)" : "it was granted but ownership never arrived")); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"skipping {((Object)item2).name} {((Object)item2).GetInstanceID()}: {arg}"); } } onReady(owned); } } [HarmonyPatch(typeof(Container), "RPC_OpenResponse")] internal static class ContainerOpenResponsePatch { private static bool Prefix(Container __instance, bool granted) { if (!ContainerAccess.Requests.ContainsKey(__instance)) { return true; } ContainerAccess.Requests[__instance] = granted; return false; } } internal class ContainerFinder { public static List<Container> FindNearbyContainers(Vector3 position, float radius) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"FindNearbyContainers with {radius} meters"); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)position); List<Container> list = new List<Container>(); Collider[] array = Physics.OverlapSphere(position, radius); global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)$"{array.Count()} colliders"); Collider[] array2 = array; foreach (Collider val in array2) { global::GrabMaterialsMod.GrabMaterialsMod.Log.LogInfo((object)(((Object)val).name ?? "")); Container component = ((Component)val).GetComponent<Container>(); ((Component)component).GetComponent<ContainerFilterService>(); if ((Object)(object)component != (Object)null) { list.Add(component); } } return list; } } [HarmonyPatch(typeof(Container), "Load")] internal class ContainerLoadPatch { private static void Postfix(Container __instance) { Boxes.ConditionallyAddContainer(__instance, "Load"); } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { Boxes.ConditionallyAddContainer(__instance, "Awake"); } } [HarmonyPatch(typeof(Container), "OnDestroyed")] internal static class ContainerOnDestroyedPatch { private static void Postfix(Container __instance) { Boxes.RemoveContainer(__instance); } } [HarmonyPatch(typeof(Player), "UpdateTeleport")] public static class PlayerUpdateTeleportPatchCleanupContainers { public static void Prefix(float dt) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsTeleporting()) { return; } foreach (Container item in from container in Boxes.Containers.ToList() where !((Object)container != (Object)null) || !((Object)((Component)container).transform != (Object)null) || container.GetInventory() == null where (Object)container != (Object)null select container) { Boxes.RemoveContainer(item); } } } [HarmonyPatch(typeof(WearNTear), "OnDestroy")] internal static class WearNTearOnDestroyPatch { private static void Prefix(WearNTear __instance) { Container[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<Container>(); Container[] componentsInParent = ((Component)__instance).GetComponentsInParent<Contai