Decompiled source of StoreAndCraft v1.6.3

plugins/StoreAndCraft/StoreAndCraft.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using Valheim.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("StoreAndCraft")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.6.3.0")]
[assembly: AssemblyInformationalVersion("1.6.3+2e309ccb7ac77bbe7db3888d2698cf06efa27cbb")]
[assembly: AssemblyProduct("StoreAndCraft")]
[assembly: AssemblyTitle("StoreAndCraft")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.3.0")]
[module: UnverifiableCode]
namespace StoreAndCraft;

public class ModConfig
{
	public const int ProtocolVersion = 22;

	public const float MaxStationCap = 50f;

	public const float MaxRange = 1000f;

	public const float LoadedAreaReach = 400f;

	public ConfigEntry<bool> LockConfig { get; }

	public ConfigEntry<bool> ModEnabled { get; }

	public ConfigEntry<bool> StoreEnabled { get; }

	public ConfigEntry<bool> AutoIntakeEnabled { get; }

	public ConfigEntry<bool> CraftEnabled { get; }

	public ConfigEntry<bool> MustHaveExisting { get; }

	public ConfigEntry<bool> LeaveOneItem { get; }

	public ConfigEntry<bool> IgnoreHotbar { get; }

	public ConfigEntry<bool> HighlightOnStore { get; }

	public ConfigEntry<bool> PingOnStore { get; }

	public ConfigEntry<float> PlayerDumpRange { get; }

	public ConfigEntry<float> StoreRange { get; }

	public ConfigEntry<float> StorageRange { get; }

	public ConfigEntry<float> DisplayRange { get; }

	public ConfigEntry<bool> AutoStackEnabled { get; }

	public ConfigEntry<float> CraftRange { get; }

	public ConfigEntry<float> AutoFillRange { get; }

	public ConfigEntry<float> AutoFillChestRange { get; }

	public ConfigEntry<float> ScarecrowRange { get; }

	public ConfigEntry<float> ScarecrowChestRange { get; }

	public ConfigEntry<bool> AutomationLoadedArea { get; }

	public ConfigEntry<float> IntakeInterval { get; }

	public ConfigEntry<int> MaxTransfersPerTick { get; }

	public ConfigEntry<KeyboardShortcut> DumpKey { get; }

	public ConfigEntry<KeyboardShortcut> HoverStoreKey { get; }

	public ConfigEntry<KeyboardShortcut> SearchKey { get; }

	public ConfigEntry<KeyboardShortcut> RenameKey { get; }

	public ConfigEntry<KeyboardShortcut> TakeStackKey { get; }

	public ConfigEntry<KeyboardShortcut> FavoriteKey { get; }

	public ConfigEntry<KeyboardShortcut> AutoFillKey { get; }

	public ConfigEntry<KeyboardShortcut> AutoDropKey { get; }

	public ConfigEntry<KeyboardShortcut> ActivityLogKey { get; }

	public ConfigEntry<bool> ActivityLogVisible { get; }

	public ConfigEntry<KeyboardShortcut> DisplayRangeKey { get; }

	public ConfigEntry<KeyboardShortcut> BuildGrabKey { get; }

	public ConfigEntry<bool> FeedTroughEnabled { get; }

	public ConfigEntry<float> FeedTroughRange { get; }

	public ConfigEntry<bool> CatchUpEnabled { get; }

	public ConfigEntry<float> CatchUpMaxHours { get; }

	public ConfigEntry<double> CatchUpSince { get; }

	public ConfigEntry<bool> TorchAutoFillDefault { get; }

	public ConfigEntry<bool> TorchAutoFillOverride { get; }

	public ConfigEntry<bool> ArmorStandSwap { get; }

	public ConfigEntry<float> KilnMaxWood { get; }

	public ConfigEntry<float> SmelterMaxOre { get; }

	public ConfigEntry<float> SmelterMaxCoal { get; }

	public ConfigEntry<float> BlastFurnaceMaxOre { get; }

	public ConfigEntry<float> BlastFurnaceMaxCoal { get; }

	public ConfigEntry<float> EitrRefineryMaxInput { get; }

	public ConfigEntry<float> EitrRefineryMaxSap { get; }

	public ConfigEntry<float> BeehiveMaxHoney { get; }

	public ConfigEntry<float> FermenterBatch { get; }

	public ConfigEntry<bool> ShowReleaseNews { get; }

	public ConfigEntry<string> ReleaseNewsSeen { get; }

	public ConfigEntry<bool> ShowBagSortButtons { get; }

	public ConfigEntry<bool> ShowChestSortButtons { get; }

	public ConfigEntry<bool> ShowStationNotices { get; }

	public ConfigEntry<string> GroundIgnoreItems { get; }

	public ConfigEntry<string> KeepInBagItems { get; }

	public ConfigEntry<string> RestockItems { get; }

	public ConfigEntry<KeyboardShortcut> RestockKey { get; }

	public ModConfig(ConfigFile file)
	{
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Expected O, but got Unknown
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017f: Expected O, but got Unknown
		//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Expected O, but got Unknown
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d5: Expected O, but got Unknown
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Expected O, but got Unknown
		//IL_023d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0247: Expected O, but got Unknown
		//IL_0268: Unknown result type (might be due to invalid IL or missing references)
		//IL_0272: Expected O, but got Unknown
		//IL_0293: Unknown result type (might be due to invalid IL or missing references)
		//IL_029d: Expected O, but got Unknown
		//IL_02be: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c8: Expected O, but got Unknown
		//IL_0338: Unknown result type (might be due to invalid IL or missing references)
		//IL_0362: Unknown result type (might be due to invalid IL or missing references)
		//IL_0389: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_0413: Unknown result type (might be due to invalid IL or missing references)
		//IL_043a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0461: Unknown result type (might be due to invalid IL or missing references)
		//IL_048b: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b7: Invalid comparison between Unknown and I4
		//IL_052a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0551: Unknown result type (might be due to invalid IL or missing references)
		//IL_059d: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a7: Expected O, but got Unknown
		//IL_05f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_05fc: Expected O, but got Unknown
		//IL_073c: Unknown result type (might be due to invalid IL or missing references)
		//IL_07bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_07c6: Expected O, but got Unknown
		//IL_07e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_07f1: Expected O, but got Unknown
		//IL_0812: Unknown result type (might be due to invalid IL or missing references)
		//IL_081c: Expected O, but got Unknown
		//IL_083d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0847: Expected O, but got Unknown
		//IL_0868: Unknown result type (might be due to invalid IL or missing references)
		//IL_0872: Expected O, but got Unknown
		//IL_0893: Unknown result type (might be due to invalid IL or missing references)
		//IL_089d: Expected O, but got Unknown
		//IL_08be: Unknown result type (might be due to invalid IL or missing references)
		//IL_08c8: Expected O, but got Unknown
		//IL_08e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_08f3: Expected O, but got Unknown
		//IL_0922: Unknown result type (might be due to invalid IL or missing references)
		//IL_092c: Expected O, but got Unknown
		//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
		AcceptableValueRange<float> val = new AcceptableValueRange<float>(0f, 1000f);
		LockConfig = file.Bind<bool>("1 - General", "LockConfig", true, "If true (recommended on dedicated), gameplay values below are owned by the SERVER. Edit com.morda.storeandcraft.cfg on the server only — clients receive them on join. Hotkeys stay local.");
		ModEnabled = file.Bind<bool>("1 - General", "ModEnabled", true, "Turns the whole mod on or off without uninstalling.");
		StoreEnabled = file.Bind<bool>("2 - Store", "StoreEnabled", true, "If enabled, dump / middle-click store, take-stack, and auto-stack work. Ground auto-store is controlled separately by AutoIntakeEnabled.");
		AutoIntakeEnabled = file.Bind<bool>("2 - Store", "AutoIntakeEnabled", true, "If enabled, ground items are pulled into nearby matching chests automatically. Turn off to leave drops on the ground (feed pets, trade) while dump / middle-click still work. Synced from server when LockConfig is on. Chat: /store enable|disable.");
		CraftEnabled = file.Bind<bool>("3 - Craft", "CraftEnabled", true, "If enabled, crafting, building, station refill ([E] on smelters, kilns, ovens, torches, fires, fermenters, turrets), and kiln/smelter/torch auto-fill can use items stored in nearby chests.");
		MustHaveExisting = file.Bind<bool>("2 - Store", "MustHaveExisting", true, "If enabled, a chest only accepts an item if that item is already inside it. Empty chests will not vacuum new item types.");
		LeaveOneItem = file.Bind<bool>("3 - Craft", "LeaveOneItem", true, "If enabled, every pull from a chest (craft, build, plant, station [E], Ctrl+middle-click fill) leaves 1 item so auto-store can keep filling that stack. That leftover item cannot be spent (same as smelter [E]).");
		IgnoreHotbar = file.Bind<bool>("2 - Store", "IgnoreHotbar", true, "If enabled, dump will not move items from the hotbar (first inventory row). Equipment / quick-slot mod overflow (outside the live bag grid) is always skipped. Wider/Deeper Pockets bag rows are dumped normally.");
		HighlightOnStore = file.Bind<bool>("2 - Store", "HighlightOnStore", true, "If enabled, a chest flashes when something is stored into it.");
		PingOnStore = file.Bind<bool>("2 - Store", "PingOnStore", false, "If enabled, a map ping is placed on the chest after a store.");
		PlayerDumpRange = file.Bind<float>("2 - Store", "PlayerDumpRange", 8f, new ConfigDescription("Dump / middle-click store range in meters (player → chest). Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		StoreRange = file.Bind<float>("2 - Store", "StoreRange", 10f, new ConfigDescription("Auto-store range in meters (ground item → chest). Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		StorageRange = file.Bind<float>("2 - Store", "StorageRange", 10f, new ConfigDescription("Extra reach for take-stack and search (meters). Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		DisplayRange = file.Bind<float>("2 - Store", "DisplayRange", 10f, new ConfigDescription("Not used any more: every Storage Display sets its own range with Alt+R (5–50 m, 10 m until set). Kept so config files and the server sync stay compatible.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		AutoStackEnabled = file.Bind<bool>("2 - Store", "AutoStackEnabled", false, "If enabled, stacks already inside a chest are compacted toward the Valheim max. Never moves items from your inventory; dump and middle-click do that.");
		CraftRange = file.Bind<float>("3 - Craft", "CraftRange", 20f, new ConfigDescription("Craft / build / station-[E] pull range in meters (player → chest). Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		AutoFillRange = file.Bind<float>("3 - Craft", "AutoFillRange", 20f, new ConfigDescription("Auto-fill range in meters: player → station (kiln/smelter/blast furnace/oven/fermenter/torch). Stations farther away pause until you come closer. Chests are searched around each station (see AutoFillChestRange). Auto-fill never takes from your bag, only from matching linked / untagged chests. Independent from CraftRange. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		AutoFillChestRange = file.Bind<float>("3 - Craft", "AutoFillChestRange", 0f, new ConfigDescription("Station → chest range in meters for auto-fill materials and auto-store output. 0 = same as AutoFillRange. Tip: large AutoFillRange (e.g. 80) with a small AutoFillChestRange (e.g. 10) keeps a whole base running while each station only uses chests right next to it. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		ScarecrowRange = file.Bind<float>("3 - Craft", "ScarecrowRange", 0f, new ConfigDescription("Scarecrow range in meters: player → scarecrow. It plants and harvests only while you are at most this far away. 0 = same as AutoFillRange. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		ScarecrowChestRange = file.Bind<float>("3 - Craft", "ScarecrowChestRange", 0f, new ConfigDescription("Scarecrow → chest range in meters: chests that supply its seeds and take its harvest. 0 = same as AutoFillChestRange (and that one 0 = AutoFillRange). Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		AutomationLoadedArea = file.Bind<bool>("3 - Craft", "AutomationLoadedArea", true, "Auto-fill, auto-store and scarecrows work everywhere in the area loaded around a player, not only within AutoFillRange / StoreRange / ScarecrowRange of the player. Stations and ground items still only use chests within their own chest range. Off = the player ranges as before. Synced from server when LockConfig is on.");
		IntakeInterval = file.Bind<float>("2 - Store", "IntakeInterval", 5f, "Seconds between automatic scans for ground items. Lower = snappier, higher = less CPU.");
		MaxTransfersPerTick = file.Bind<int>("1 - General", "MaxTransfersPerTick", 8, "Maximum item moves per frame. Raise only if storing feels too slow.");
		DumpKey = file.Bind<KeyboardShortcut>("4 - Keys", "DumpKey", new KeyboardShortcut((KeyCode)46, Array.Empty<KeyCode>()), "Hotkey: move allowed inventory stacks into nearby chests that already hold those items.");
		HoverStoreKey = file.Bind<KeyboardShortcut>("4 - Keys", "HoverStoreKey", new KeyboardShortcut((KeyCode)325, Array.Empty<KeyCode>()), "Hotkey: store only the inventory item under the cursor into a nearby chest that already holds it.");
		SearchKey = file.Bind<KeyboardShortcut>("4 - Keys", "SearchKey", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), "While inventory is open: hover an item and press to ping/blink the nearest chest that contains it (blinks 3 times).");
		RenameKey = file.Bind<KeyboardShortcut>("4 - Keys", "RenameKey", new KeyboardShortcut((KeyCode)101, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Settings (default Alt+E): look at a chest (name / ignore / display / link), a small Storage Display (name/amount), or a multi-input kiln/smelter/grill (pull filter + link). Shift+E opens it only if you set Shift+E here (other mods can use Shift+E otherwise). Prefix [I] = fully ignore; [H] = hide from dump/store/craft but still show on Storage Displays; [M] = manual fill (no dump/intake into chest, station pull + [lN] links still work).");
		TakeStackKey = file.Bind<KeyboardShortcut>("4 - Keys", "TakeStackKey", new KeyboardShortcut((KeyCode)325, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Hotkey: fill the hovered inventory stack from nearby chests, only up to max stack / carry weight.");
		FavoriteKey = file.Bind<KeyboardShortcut>("4 - Keys", "FavoriteKey", new KeyboardShortcut((KeyCode)102, Array.Empty<KeyCode>()), "Hotkey: while inventory is open, hover an item and press to favorite / unfavorite. Favorites are skipped by dump, hover-store, and inventory sort (local, not synced).");
		AutoFillKey = file.Bind<KeyboardShortcut>("4 - Keys", "AutoFillKey", new KeyboardShortcut((KeyCode)98, Array.Empty<KeyCode>()), "Look at a kiln, smelter, blast furnace, cooking / stone oven, fermenter, or torch / fire with the inventory closed and press to toggle auto-fill. The station pull filter still applies. Local, not synced.");
		AutoDropKey = file.Bind<KeyboardShortcut>("4 - Keys", "AutoDropKey", new KeyboardShortcut((KeyCode)110, Array.Empty<KeyCode>()), "Look at a kiln/smelter/blast furnace, cooking spit/oven, fermenter, or beehive with the inventory closed and press to toggle auto-store. Finished bars / food / mead / honey go into a nearby chest (ground only if no space). Independent from auto-fill (B). Per piece.");
		ActivityLogKey = file.Bind<KeyboardShortcut>("4 - Keys", "ActivityLogKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Opens the StoreAndCraft panel: activity log checkbox (anyone, local) and range sliders with Save (host / server admin from the adminlist; everyone in an offline / own world). Do not use F11, Valheim saves a screenshot on F11.");
		KeyboardShortcut value = ActivityLogKey.Value;
		if ((int)((KeyboardShortcut)(ref value)).MainKey == 292)
		{
			value = ActivityLogKey.Value;
			if (!((KeyboardShortcut)(ref value)).Modifiers.GetEnumerator().MoveNext())
			{
				ActivityLogKey.Value = new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>());
			}
		}
		ActivityLogVisible = file.Bind<bool>("4 - Keys", "ActivityLogVisible", false, "Remember whether the activity log is shown. Local only, not synced. Changed by the F10 panel checkbox.");
		DisplayRangeKey = file.Bind<KeyboardShortcut>("4 - Keys", "DisplayRangeKey", new KeyboardShortcut((KeyCode)114, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Look at a Storage Display and press to set that board's chest-scan range (5–50 m). Per display.");
		BuildGrabKey = file.Bind<KeyboardShortcut>("4 - Keys", "BuildGrabKey", new KeyboardShortcut((KeyCode)99, Array.Empty<KeyCode>()), "Hold this key while confirming a hammer place to grab that piece's materials from nearby chests (nothing is placed). Default C — Shift stays free for no-snap. Local, not synced.");
		FeedTroughEnabled = file.Bind<bool>("5 - Feed Trough", "FeedTroughEnabled", true, "If enabled, the Feed Trough hammer piece is available. Hungry tames walk to it and eat matching food, like drops on the ground. Synced from server when LockConfig is on.");
		FeedTroughRange = file.Bind<float>("5 - Feed Trough", "FeedTroughRange", 8f, new ConfigDescription("How far (meters) hungry animals notice a Feed Trough and walk to it. Also limited by each animal's own food-search range. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val, Array.Empty<object>()));
		CatchUpEnabled = file.Bind<bool>("3 - Craft", "CatchUpWhileAway", false, "Kilns / smelters / blast furnaces / windmills / spinning wheels / eitr refineries with auto-fill (B) AND auto-store (N) catch up the time their zone was unloaded (nobody nearby). When someone comes back, ore + fuel are taken from the chests and the finished items are put into a chest, in packages of one stack. Only time after switching this on counts. Synced from server when LockConfig is on.");
		CatchUpMaxHours = file.Bind<float>("3 - Craft", "CatchUpMaxHours", 8f, new ConfigDescription("Most game time (hours) one station catches up after being unloaded. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 48f), Array.Empty<object>()));
		CatchUpSince = file.Bind<double>("3 - Craft", "CatchUpSince", 0.0, "Set automatically: world time (seconds) when CatchUpWhileAway was switched on. Time before this is never caught up. Do not edit.");
		TorchAutoFillDefault = file.Bind<bool>("3 - Craft", "TorchAutoFillDefault", false, "Auto-fill state of torches (standing, wall, green / blue / mist, modded *torch*) that are placed from now on. On = new torches start with auto-fill ON, off = B needed. Placed torches are never changed by this. B on a torch still switches it. Synced from server when LockConfig is on.");
		TorchAutoFillOverride = file.Bind<bool>("3 - Craft", "TorchAutoFillOverride", false, "World Override: while on, auto-fill is active on EVERY torch, including already placed ones, whatever their own B setting says. The torches' own setting is not changed, so switching this off brings it back. Synced from server when LockConfig is on.");
		ShowReleaseNews = file.Bind<bool>("1 - General", "ShowReleaseNews", true, "After an update, Hugin (the raven) visits once and tells you what is new in StoreAndCraft. Local only, not synced.");
		ArmorStandSwap = file.Bind<bool>("1 - General", "ArmorStandSwap", true, "Armor stand: [E] swaps the armor on the stand with the armor you wear (helmet, chest, legs, cape) instead of dropping it on the ground. Off = vanilla. Synced from server when LockConfig is on.");
		ShowBagSortButtons = file.Bind<bool>("1 - General", "ShowBagSortButtons", true, "Show the Stack and Sort buttons on top of your inventory. Local only, not synced.");
		ShowChestSortButtons = file.Bind<bool>("1 - General", "ShowChestSortButtons", true, "Show the Stack and Sort buttons next to Take all on the chest panel. Local only, not synced.");
		ShowStationNotices = file.Bind<bool>("1 - General", "ShowStationNotices", true, "Show the notice above a station when its output has nowhere to go: Chest full, No linked chest, No chest nearby. Only the text: a smelter still waits while its chest is full. Local only, not synced.");
		GroundIgnoreItems = file.Bind<string>("2 - Store", "GroundIgnoreItems", "", "Items auto-store never picks up from the ground (e.g. eggs). Item names separated by commas, set in the F10 panel. Local only, not synced.");
		RestockItems = file.Bind<string>("2 - Store", "RestockItems", "", "Items of the keep list that the restock key fills up to their amount from nearby chests. Item names separated by commas, set in the F10 panel (the Fill box of a tile). Local only, not synced.");
		RestockKey = file.Bind<KeyboardShortcut>("4 - Keys", "RestockKey", new KeyboardShortcut((KeyCode)48, Array.Empty<KeyCode>()), "Hotkey: bring the items marked Fill in the keep list (F10) up to their amount from nearby chests. Chests set to Ignore or Only stations are skipped, the carry weight is not a limit. Local only, not synced.");
		KeepInBagItems = file.Bind<string>("2 - Store", "KeepInBagItems", "", "Items dump leaves in your inventory: name=amount separated by commas (e.g. $item_wood=10), set in the F10 panel. Only the dump key, not middle-click. Local only, not synced.");
		ReleaseNewsSeen = file.Bind<string>("1 - General", "ReleaseNewsSeen", "", "Set automatically: the StoreAndCraft version whose news Hugin already told you. Do not edit.");
		AcceptableValueRange<float> val2 = new AcceptableValueRange<float>(0f, 50f);
		KilnMaxWood = file.Bind<float>("6 - Stations", "KilnMaxWood", 0f, new ConfigDescription("Charcoal kiln: most wood in the queue. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		SmelterMaxOre = file.Bind<float>("6 - Stations", "SmelterMaxOre", 0f, new ConfigDescription("Smelter: most ore in the queue. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		SmelterMaxCoal = file.Bind<float>("6 - Stations", "SmelterMaxCoal", 0f, new ConfigDescription("Smelter: most coal. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		BlastFurnaceMaxOre = file.Bind<float>("6 - Stations", "BlastFurnaceMaxOre", 0f, new ConfigDescription("Blast furnace: most ore in the queue. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		BlastFurnaceMaxCoal = file.Bind<float>("6 - Stations", "BlastFurnaceMaxCoal", 0f, new ConfigDescription("Blast furnace: most coal. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		EitrRefineryMaxInput = file.Bind<float>("6 - Stations", "EitrRefineryMaxInput", 0f, new ConfigDescription("Eitr refinery: most soft tissue in the queue. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		EitrRefineryMaxSap = file.Bind<float>("6 - Stations", "EitrRefineryMaxSap", 0f, new ConfigDescription("Eitr refinery: most sap. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		BeehiveMaxHoney = file.Bind<float>("6 - Stations", "BeehiveMaxHoney", 0f, new ConfigDescription("Beehive: most honey it collects before it is full. 0 = vanilla, otherwise 1-50. Applied live to every station. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)val2, Array.Empty<object>()));
		FermenterBatch = file.Bind<float>("6 - Stations", "FermenterBatch", 5f, new ConfigDescription("Fermenter: how many of the same mead base fit in one batch. More can be added only in the first 60 seconds; all finish in the time of one. 1 = vanilla. Synced from server when LockConfig is on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
	}

	public float StationPullRange()
	{
		return Mathf.Max(CraftRange.Value, AutoFillRange.Value);
	}

	public float AutoFillChestReach()
	{
		if (!AutomationLoadedArea.Value)
		{
			return AutoFillChestMeters();
		}
		return 400f;
	}

	public float AutoFillChestMeters()
	{
		float value = AutoFillChestRange.Value;
		if (!(value > 0f))
		{
			return AutoFillRange.Value;
		}
		return value;
	}

	public float ScarecrowReach()
	{
		if (!(ScarecrowRange.Value > 0f))
		{
			return AutoFillRange.Value;
		}
		return ScarecrowRange.Value;
	}

	public float ScarecrowChestReach()
	{
		if (!AutomationLoadedArea.Value)
		{
			return ScarecrowChestMeters();
		}
		return 400f;
	}

	public float ScarecrowChestMeters()
	{
		if (!(ScarecrowChestRange.Value > 0f))
		{
			return AutoFillChestMeters();
		}
		return ScarecrowChestRange.Value;
	}

	public float DumpReach()
	{
		return Reach(PlayerDumpRange);
	}

	public float CraftReach()
	{
		return Reach(CraftRange);
	}

	public float StorageReach()
	{
		return Reach(StorageRange);
	}

	public float StoreReach()
	{
		return Reach(StoreRange);
	}

	private float Reach(ConfigEntry<float> meters)
	{
		if (!AutomationLoadedArea.Value)
		{
			return meters.Value;
		}
		return 400f;
	}

	public float AutoFillPlayerReach()
	{
		if (!AutomationLoadedArea.Value)
		{
			return AutoFillRange.Value;
		}
		return 400f;
	}

	public float ScarecrowPlayerReach()
	{
		if (!AutomationLoadedArea.Value)
		{
			return ScarecrowReach();
		}
		return 400f;
	}

	public float AutoFillPlayerToChestRange()
	{
		return Mathf.Max(AutoFillRange.Value + AutoFillChestMeters(), ScarecrowReach() + ScarecrowChestMeters());
	}

	public float MaxGameplayRange()
	{
		return Mathf.Max(new float[8]
		{
			PlayerDumpRange.Value,
			StoreRange.Value,
			StorageRange.Value,
			DisplayRange.Value,
			CraftRange.Value,
			AutoFillRange.Value,
			ScarecrowReach(),
			FeedTroughRange.Value
		});
	}

	public void WriteToPackage(ZPackage pkg)
	{
		pkg.Write(LockConfig.Value);
		pkg.Write(ModEnabled.Value);
		pkg.Write(StoreEnabled.Value);
		pkg.Write(AutoIntakeEnabled.Value);
		pkg.Write(CraftEnabled.Value);
		pkg.Write(MustHaveExisting.Value);
		pkg.Write(LeaveOneItem.Value);
		pkg.Write(PlayerDumpRange.Value);
		pkg.Write(StoreRange.Value);
		pkg.Write(StorageRange.Value);
		pkg.Write(DisplayRange.Value);
		pkg.Write(AutoStackEnabled.Value);
		pkg.Write(CraftRange.Value);
		pkg.Write(AutoFillRange.Value);
		pkg.Write(IntakeInterval.Value);
		pkg.Write(MaxTransfersPerTick.Value);
		pkg.Write(FeedTroughEnabled.Value);
		pkg.Write(FeedTroughRange.Value);
		pkg.Write(AutoFillChestRange.Value);
		pkg.Write(CatchUpEnabled.Value);
		pkg.Write(CatchUpMaxHours.Value);
		pkg.Write(CatchUpSince.Value);
		pkg.Write(TorchAutoFillDefault.Value);
		pkg.Write(KilnMaxWood.Value);
		pkg.Write(SmelterMaxOre.Value);
		pkg.Write(SmelterMaxCoal.Value);
		pkg.Write(BlastFurnaceMaxOre.Value);
		pkg.Write(BlastFurnaceMaxCoal.Value);
		pkg.Write(EitrRefineryMaxInput.Value);
		pkg.Write(EitrRefineryMaxSap.Value);
		pkg.Write(BeehiveMaxHoney.Value);
		pkg.Write(FermenterBatch.Value);
		pkg.Write(TorchAutoFillOverride.Value);
		pkg.Write(ArmorStandSwap.Value);
		pkg.Write(ScarecrowRange.Value);
		pkg.Write(ScarecrowChestRange.Value);
		pkg.Write(AutomationLoadedArea.Value);
	}

	public void ReadFromPackage(ZPackage pkg)
	{
		LockConfig.Value = pkg.ReadBool();
		ModEnabled.Value = pkg.ReadBool();
		StoreEnabled.Value = pkg.ReadBool();
		AutoIntakeEnabled.Value = pkg.ReadBool();
		CraftEnabled.Value = pkg.ReadBool();
		MustHaveExisting.Value = pkg.ReadBool();
		LeaveOneItem.Value = pkg.ReadBool();
		PlayerDumpRange.Value = pkg.ReadSingle();
		StoreRange.Value = pkg.ReadSingle();
		StorageRange.Value = pkg.ReadSingle();
		DisplayRange.Value = pkg.ReadSingle();
		AutoStackEnabled.Value = pkg.ReadBool();
		CraftRange.Value = pkg.ReadSingle();
		AutoFillRange.Value = pkg.ReadSingle();
		IntakeInterval.Value = pkg.ReadSingle();
		MaxTransfersPerTick.Value = pkg.ReadInt();
		FeedTroughEnabled.Value = pkg.ReadBool();
		FeedTroughRange.Value = pkg.ReadSingle();
		AutoFillChestRange.Value = pkg.ReadSingle();
		CatchUpEnabled.Value = pkg.ReadBool();
		CatchUpMaxHours.Value = pkg.ReadSingle();
		CatchUpSince.Value = pkg.ReadDouble();
		TorchAutoFillDefault.Value = pkg.ReadBool();
		KilnMaxWood.Value = pkg.ReadSingle();
		SmelterMaxOre.Value = pkg.ReadSingle();
		SmelterMaxCoal.Value = pkg.ReadSingle();
		BlastFurnaceMaxOre.Value = pkg.ReadSingle();
		BlastFurnaceMaxCoal.Value = pkg.ReadSingle();
		EitrRefineryMaxInput.Value = pkg.ReadSingle();
		EitrRefineryMaxSap.Value = pkg.ReadSingle();
		BeehiveMaxHoney.Value = pkg.ReadSingle();
		FermenterBatch.Value = pkg.ReadSingle();
		TorchAutoFillOverride.Value = pkg.ReadBool();
		ArmorStandSwap.Value = pkg.ReadBool();
		if (pkg.GetPos() < pkg.Size())
		{
			ScarecrowRange.Value = pkg.ReadSingle();
		}
		if (pkg.GetPos() < pkg.Size())
		{
			ScarecrowChestRange.Value = pkg.ReadSingle();
		}
		if (pkg.GetPos() < pkg.Size())
		{
			AutomationLoadedArea.Value = pkg.ReadBool();
		}
	}
}
internal static class ArmorStandPanel
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static UnityAction <>9__17_0;

		internal void <Build>b__17_0()
		{
			UnityAction close = _close;
			if (close != null)
			{
				close.Invoke();
			}
		}
	}

	private const float PanelW = 330f;

	private const float Pad = 24f;

	private const float RowH = 40f;

	private const float RowGap = 8f;

	private const float CellW = 92f;

	private const float CellH = 92f;

	private static readonly Color Gold = new Color(0.925f, 0.77f, 0.29f, 1f);

	private static readonly Color Muted = new Color(0.78f, 0.72f, 0.6f, 0.9f);

	private static RectTransform _root;

	private static ArmorStand _stand;

	private static UnityAction _close;

	private static GameObject _panel;

	private static GameObject _list;

	private static int _openSlot = -1;

	internal static void Create(RectTransform root, ArmorStand stand, UnityAction close)
	{
		_root = root;
		_stand = stand;
		_close = close;
		_openSlot = -1;
		Build();
	}

	internal static void Rebuild()
	{
		if (!((Object)(object)_root == (Object)null) && !((Object)(object)_stand == (Object)null))
		{
			Build();
		}
	}

	internal static void Dispose()
	{
		_root = null;
		_stand = null;
		_close = null;
		_panel = null;
		_list = null;
		_openSlot = -1;
	}

	private static void Build()
	{
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: 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_0109: Expected O, but got Unknown
		//IL_0124: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_015d: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_018a: Unknown result type (might be due to invalid IL or missing references)
		//IL_018f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Expected O, but got Unknown
		//IL_0202: Unknown result type (might be due to invalid IL or missing references)
		//IL_0211: Unknown result type (might be due to invalid IL or missing references)
		//IL_021b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_033d: Unknown result type (might be due to invalid IL or missing references)
		//IL_034c: Unknown result type (might be due to invalid IL or missing references)
		//IL_036f: Unknown result type (might be due to invalid IL or missing references)
		//IL_037b: Expected O, but got Unknown
		//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)_panel != (Object)null)
		{
			Object.Destroy((Object)(object)_panel);
		}
		if ((Object)(object)_list != (Object)null)
		{
			Object.Destroy((Object)(object)_list);
		}
		_panel = null;
		_list = null;
		ArmorStand stand = _stand;
		ZNetView val = ArmorStandSwap.ViewOf(stand);
		ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null);
		List<int> list = new List<int>();
		for (int i = 0; i < stand.m_slots.Count; i++)
		{
			if (ArmorStandSwap.IsPresetSlot(stand, i) && stand.HaveAttachment(i))
			{
				list.Add(i);
			}
		}
		float num = 70f;
		float num2 = 108f + (float)Mathf.Max(1, list.Count) * num + 24f - 8f;
		_panel = ScarecrowPanel.NewFrame(_root, "SAC_ArmorStandPanel", new Vector2(30f, -150f), new Vector2(330f, num2));
		RectTransform parent = (RectTransform)_panel.transform;
		ScarecrowPanel.Label(parent, Loc.T("Armor stand", "Rüstungsständer"), new Vector2(24f, -22f), new Vector2(246f, 26f), 20f, Gold, (TextAlignmentOptions)257);
		Vector2 pos = new Vector2(278f, -20f);
		Vector2 size = new Vector2(28f, 28f);
		object obj = <>c.<>9__17_0;
		if (obj == null)
		{
			UnityAction val3 = delegate
			{
				UnityAction close = _close;
				if (close != null)
				{
					close.Invoke();
				}
			};
			<>c.<>9__17_0 = val3;
			obj = (object)val3;
		}
		ScarecrowPanel.Button(parent, "X", pos, size, "X", (UnityAction)obj, on: false);
		ScarecrowPanel.Label(parent, Loc.T("Choose which item from your bag [E] swaps with the piece on the stand.", "Wähle, welches Teil aus deinem Inventar [E] mit dem Teil auf dem Ständer tauscht."), new Vector2(24f, -56f), new Vector2(282f, 44f), 14f, Muted, (TextAlignmentOptions)257);
		if (list.Count == 0)
		{
			ScarecrowPanel.Label(parent, Loc.T("Put a weapon, shield or tool on the stand first.", "Lege zuerst eine Waffe, einen Schild oder ein Werkzeug auf den Ständer."), new Vector2(24f, -108f), new Vector2(282f, 24f), 15f, Muted, (TextAlignmentOptions)257);
			return;
		}
		float num3 = 108f;
		for (int num4 = 0; num4 < list.Count; num4++)
		{
			int slot = list[num4];
			ItemData val4 = ((val2 != null && stand.HaveAttachment(slot)) ? ArmorStandSwap.StandItem(stand, val2, slot) : null);
			ItemData val5 = ((val2 != null) ? ArmorStandSwap.PresetAsItem(val2, slot) : null);
			string text = ((val4 != null) ? StationPullFilter.DisplayName(val4.m_shared.m_name) : Loc.T("empty", "leer"));
			ScarecrowPanel.Label(parent, Loc.T("On the stand: ", "Auf dem Ständer: ") + text, new Vector2(24f, 0f - num3), new Vector2(282f, 22f), 14f, Muted, (TextAlignmentOptions)257);
			string text2 = ((val5 != null) ? ItemText(val5) : Loc.T("choose...", "wählen..."));
			bool flag = _openSlot == slot;
			RectTransform parent2 = ScarecrowPanel.Button(parent, "Crop", new Vector2(24f, 0f - (num3 + 22f)), new Vector2(282f, 40f), Loc.T("Swap with: ", "Tausch mit: ") + text2, (UnityAction)delegate
			{
				_openSlot = ((_openSlot == slot) ? (-1) : slot);
				Build();
			}, flag);
			Sprite val6 = ((val5 != null) ? val5.GetIcon() : null);
			if ((Object)(object)val6 != (Object)null)
			{
				ScarecrowPanel.IconImage(parent2, val6, new Vector2(8f, -6f), 28f);
			}
			num3 += num;
		}
		if (_openSlot >= 0)
		{
			BuildItemList();
		}
	}

	private static void BuildItemList()
	{
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0163: Unknown result type (might be due to invalid IL or missing references)
		//IL_017c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0183: Expected O, but got Unknown
		//IL_0294: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bd: Expected O, but got Unknown
		//IL_01da: 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_030c: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0325: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_025b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0214: Unknown result type (might be due to invalid IL or missing references)
		//IL_0219: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Expected O, but got Unknown
		//IL_0221: Expected O, but got Unknown
		ArmorStand stand = _stand;
		int slot = _openSlot;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)stand == (Object)null || (Object)(object)localPlayer == (Object)null || slot < 0 || slot >= stand.m_slots.Count)
		{
			return;
		}
		List<ItemType> supportedTypes = stand.m_slots[slot].m_supportedTypes;
		List<ItemData> list = new List<ItemData>();
		HashSet<string> hashSet = new HashSet<string>();
		foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
		{
			if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && supportedTypes.Contains(allItem.m_shared.m_itemType) && ArmorStandSwap.StandCanShow(allItem) && hashSet.Add(((Object)allItem.m_dropPrefab).name + "#" + allItem.m_quality))
			{
				list.Add(allItem);
			}
		}
		int num = list.Count + 1;
		int num2 = Mathf.Max(1, (num + 4 - 1) / 4);
		float num3 = 422f;
		float num4 = 36f + (float)num2 * 92f + (float)(num2 - 1) * 6f;
		_list = ScarecrowPanel.NewFrame(_root, "SAC_ArmorStandItems", new Vector2(368f, -150f), new Vector2(num3, num4));
		RectTransform parent = (RectTransform)_list.transform;
		Vector2 val = default(Vector2);
		UnityAction val2 = default(UnityAction);
		for (int i = 0; i < num; i++)
		{
			int num5 = i % 4;
			int num6 = i / 4;
			((Vector2)(ref val))..ctor(18f + (float)num5 * 98f, 0f - (18f + (float)num6 * 98f));
			if (i == 0)
			{
				Vector2 pos = val;
				Vector2 size = new Vector2(92f, 92f);
				UnityAction obj = val2;
				if (obj == null)
				{
					UnityAction val3 = delegate
					{
						Pick(slot, null);
					};
					UnityAction val4 = val3;
					val2 = val3;
					obj = val4;
				}
				ScarecrowPanel.Label(ScarecrowPanel.Button(parent, "None", pos, size, "", obj, on: false), Loc.T("None", "Keine"), new Vector2(4f, -30f), new Vector2(84f, 34f), 15f, Muted, (TextAlignmentOptions)258);
			}
			else
			{
				ItemData item = list[i - 1];
				RectTransform parent2 = ScarecrowPanel.Button(parent, "Item" + i, val, new Vector2(92f, 92f), "", (UnityAction)delegate
				{
					Pick(slot, item);
				}, on: false);
				Sprite icon = item.GetIcon();
				if ((Object)(object)icon != (Object)null)
				{
					ScarecrowPanel.IconImage(parent2, icon, new Vector2(24f, -8f), 44f);
				}
				ScarecrowPanel.Label(parent2, ItemText(item), new Vector2(4f, -54f), new Vector2(84f, 34f), 12f, Muted, (TextAlignmentOptions)258);
			}
		}
	}

	private static void Pick(int slot, ItemData item)
	{
		if (!((Object)(object)_stand == (Object)null))
		{
			ArmorStandSwap.SetPreset(_stand, slot, item);
			_openSlot = -1;
			Build();
		}
	}

	private static string ItemText(ItemData item)
	{
		string text = StationPullFilter.DisplayName(item.m_shared.m_name);
		if (item.m_quality <= 1)
		{
			return text;
		}
		return text + " (" + item.m_quality + ")";
	}
}
internal static class ArmorStandSwap
{
	private static readonly FieldInfo NviewField = AccessTools.Field(typeof(ArmorStand), "m_nview");

	private const string PresetItemKey = "SAC_swapItem";

	private static readonly int PresetItemKeyHash = StringExtensionMethods.GetStableHashCode("SAC_swapItem");

	private const string PresetQualityKey = "SAC_swapQ";

	private static readonly int PresetQualityKeyHash = StringExtensionMethods.GetStableHashCode("SAC_swapQ");

	internal static bool Enabled
	{
		get
		{
			if (Plugin.Settings != null && Plugin.Settings.ModEnabled.Value)
			{
				return Plugin.Settings.ArmorStandSwap.Value;
			}
			return false;
		}
	}

	internal static bool IsArmor(ItemType t)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Invalid comparison between Unknown and I4
		if ((int)t != 6 && (int)t != 7 && (int)t != 11)
		{
			return (int)t == 17;
		}
		return true;
	}

	internal static bool StandCanShow(ItemData item)
	{
		//IL_0019: 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_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Invalid comparison between Unknown and I4
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0026: Invalid comparison between Unknown and I4
		if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
		{
			return false;
		}
		ItemType itemType = item.m_shared.m_itemType;
		if ((int)itemType == 11 || (int)itemType == 7)
		{
			return true;
		}
		Transform transform = item.m_dropPrefab.transform;
		for (int i = 0; i < transform.childCount; i++)
		{
			string name = ((Object)((Component)transform.GetChild(i)).gameObject).name;
			if (name == "attach" || name == "attach_skin")
			{
				return true;
			}
		}
		return false;
	}

	internal static ItemData StandItem(ArmorStand stand, ZDO zdo, int slot)
	{
		int attachedItem = stand.GetAttachedItem(slot);
		if (attachedItem == 0 || (Object)(object)ObjectDB.instance == (Object)null)
		{
			return null;
		}
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(attachedItem);
		ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		ItemData obj = val.m_itemData.Clone();
		obj.m_dropPrefab = itemPrefab;
		ItemDrop.LoadFromZDO(obj, zdo, slot);
		obj.m_stack = 1;
		obj.m_equipped = false;
		return obj;
	}

	internal static bool TrySwap(ArmorStand stand, Switch caller, Humanoid user)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
		Player val = (Player)(object)((user is Player) ? user : null);
		if (!Enabled || (Object)(object)stand == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
		{
			return false;
		}
		if (!PrivateArea.CheckAccess(((Component)stand).transform.position, 0f, false, false))
		{
			return false;
		}
		ZNetView val2 = (ZNetView)((NviewField != null) ? /*isinst with value type is only supported in some contexts*/: null);
		if ((Object)(object)val2 == (Object)null || !val2.IsValid() || val2.GetZDO() == null)
		{
			return false;
		}
		int num = SlotOf(stand, caller);
		if (num < 0)
		{
			return false;
		}
		ZDO zDO = val2.GetZDO();
		ItemData val3 = StandItem(stand, zDO, num);
		if (val3 == null)
		{
			return false;
		}
		if (!val2.IsOwner())
		{
			val2.ClaimOwnership();
		}
		if (!val2.IsOwner())
		{
			return false;
		}
		int num2 = 0;
		bool flag = false;
		bool flag2 = false;
		for (int i = 0; i < stand.m_slots.Count; i++)
		{
			if (!stand.HaveAttachment(i))
			{
				continue;
			}
			ItemData val4 = StandItem(stand, zDO, i);
			if (val4 != null && IsArmor(val4.m_shared.m_itemType))
			{
				if (SwapSlot(stand, val2, zDO, val, i, val4))
				{
					num2++;
				}
				else
				{
					flag = true;
				}
			}
		}
		for (int j = 0; j < stand.m_slots.Count; j++)
		{
			if (!IsPresetSlot(stand, j) || !stand.HaveAttachment(j) || !GetPreset(zDO, j, out var hash, out var quality))
			{
				continue;
			}
			ItemData val5 = StandItem(stand, zDO, j);
			if (val5 != null)
			{
				flag2 = true;
				if (SwapPreset(stand, val2, zDO, val, j, val5, hash, quality))
				{
					num2++;
				}
			}
		}
		if (flag)
		{
			((Character)val).Message((MessageType)2, "$msg_noroom", 0, (Sprite)null, false);
		}
		if (num2 > 0)
		{
			stand.m_effects.Create(((Component)stand).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
		}
		if (num2 > 0 || flag || flag2)
		{
			return true;
		}
		if (!IsArmor(val3.m_shared.m_itemType))
		{
			return TakeToBag(stand, val2, zDO, val, num, val3);
		}
		return false;
	}

	internal static bool IsPresetSlot(ArmorStand stand, int slot)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)stand == (Object)null || slot < 0 || slot >= stand.m_slots.Count)
		{
			return false;
		}
		List<ItemType> supportedTypes = stand.m_slots[slot].m_supportedTypes;
		if (supportedTypes == null || supportedTypes.Count == 0)
		{
			return false;
		}
		for (int i = 0; i < supportedTypes.Count; i++)
		{
			if (IsArmor(supportedTypes[i]))
			{
				return false;
			}
		}
		return true;
	}

	internal static int SlotOf(ArmorStand stand, Switch sw, bool occupiedOnly = true)
	{
		int num = -1;
		for (int i = 0; i < stand.m_slots.Count; i++)
		{
			if (!((Object)(object)stand.m_slots[i].m_switch != (Object)(object)sw))
			{
				if (num < 0)
				{
					num = i;
				}
				if (stand.HaveAttachment(i))
				{
					return i;
				}
			}
		}
		if (!occupiedOnly)
		{
			return num;
		}
		return -1;
	}

	internal static ZNetView ViewOf(ArmorStand stand)
	{
		if (!((Object)(object)stand != (Object)null) || !(NviewField != null))
		{
			return null;
		}
		object? value = NviewField.GetValue(stand);
		return (ZNetView)((value is ZNetView) ? value : null);
	}

	internal static bool GetPreset(ZDO zdo, int slot, out int hash, out int quality)
	{
		hash = ((zdo != null) ? zdo.GetInt("SAC_swapItem" + slot, 0) : 0);
		quality = ((zdo == null) ? 1 : zdo.GetInt("SAC_swapQ" + slot, 1));
		return hash != 0;
	}

	internal static void SetPreset(ArmorStand stand, int slot, ItemData item)
	{
		ZNetView val = ViewOf(stand);
		if (!((Object)(object)val == (Object)null) && val.IsValid() && val.GetZDO() != null && IsPresetSlot(stand, slot))
		{
			if (!val.IsOwner())
			{
				val.ClaimOwnership();
			}
			if (val.IsOwner())
			{
				ZDO zDO = val.GetZDO();
				zDO.Set("SAC_swapItem" + slot, (item != null && (Object)(object)item.m_dropPrefab != (Object)null) ? StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name) : 0);
				zDO.Set("SAC_swapQ" + slot, item?.m_quality ?? 1);
			}
		}
	}

	internal static ItemData PresetAsItem(ZDO zdo, int slot)
	{
		if (!GetPreset(zdo, slot, out var hash, out var quality) || (Object)(object)ObjectDB.instance == (Object)null)
		{
			return null;
		}
		GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(hash);
		ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null);
		if ((Object)(object)val == (Object)null)
		{
			return null;
		}
		ItemData obj = val.m_itemData.Clone();
		obj.m_dropPrefab = itemPrefab;
		obj.m_quality = quality;
		return obj;
	}

	private static ItemData FindInBag(Inventory inv, int hash, int quality)
	{
		ItemData val = null;
		foreach (ItemData allItem in inv.GetAllItems())
		{
			if (!((Object)(object)allItem.m_dropPrefab == (Object)null) && allItem.m_quality == quality && StringExtensionMethods.GetStableHashCode(((Object)allItem.m_dropPrefab).name) == hash)
			{
				if (allItem.m_equipped)
				{
					return allItem;
				}
				if (val == null)
				{
					val = allItem;
				}
			}
		}
		return val;
	}

	private static bool SwapPreset(ArmorStand stand, ZNetView nv, ZDO zdo, Player player, int slot, ItemData standItem, int presetHash, int presetQuality)
	{
		Inventory inventory = ((Humanoid)player).GetInventory();
		ItemData val = FindInBag(inventory, presetHash, presetQuality);
		if (val == null)
		{
			((Character)player).Message((MessageType)2, Loc.T("Preset item is not in your bag", "Vorlagen-Item ist nicht im Inventar"), 0, (Sprite)null, false);
			return false;
		}
		if (!StandCanShow(val))
		{
			((Character)player).Message((MessageType)2, Loc.T("The stand cannot hold this item", "Der Ständer kann das nicht halten"), 0, (Sprite)null, false);
			return false;
		}
		bool equipped = val.m_equipped;
		int stableHashCode = StringExtensionMethods.GetStableHashCode(slot + "_item");
		int stableHashCode2 = StringExtensionMethods.GetStableHashCode(slot + "_variant");
		ItemData obj = val.Clone();
		obj.m_stack = 1;
		obj.m_equipped = false;
		obj.m_dropPrefab = val.m_dropPrefab;
		int stableHashCode3 = StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name);
		zdo.Set(stableHashCode, stableHashCode3, false);
		zdo.Set(stableHashCode2, val.m_variant, false);
		ItemDrop.SaveToZDO(obj, zdo, slot);
		((Humanoid)player).UnequipItem(val, false);
		inventory.RemoveOneItem(val);
		nv.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { slot, stableHashCode3, val.m_variant });
		standItem.m_equipped = false;
		inventory.AddItem(standItem);
		if (equipped)
		{
			((Humanoid)player).EquipItem(standItem, true);
		}
		SetPreset(stand, slot, standItem);
		return true;
	}

	private static bool TakeToBag(ArmorStand stand, ZNetView nv, ZDO zdo, Player player, int slot, ItemData item)
	{
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (!inventory.CanAddItem(item, -1))
		{
			return false;
		}
		zdo.Set(StringExtensionMethods.GetStableHashCode(slot + "_item"), 0, false);
		nv.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { slot, 0, 0 });
		item.m_equipped = false;
		inventory.AddItem(item);
		((Character)player).Message((MessageType)1, "$msg_added " + item.m_shared.m_name, 1, item.GetIcon(), false);
		stand.m_effects.Create(((Component)stand).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
		return true;
	}

	private static bool SwapSlot(ArmorStand stand, ZNetView nv, ZDO zdo, Player player, int slot, ItemData standItem)
	{
		//IL_0015: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = ((Humanoid)player).GetInventory();
		ItemType type = standItem.m_shared.m_itemType;
		ItemData val = ((IEnumerable<ItemData>)inventory.GetEquippedItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => x.m_shared.m_itemType == type));
		bool flag = val != null && StandCanShow(val);
		if (!flag && !inventory.CanAddItem(standItem, -1))
		{
			return false;
		}
		int stableHashCode = StringExtensionMethods.GetStableHashCode(slot + "_item");
		int stableHashCode2 = StringExtensionMethods.GetStableHashCode(slot + "_variant");
		if (flag)
		{
			ItemData obj = val.Clone();
			obj.m_stack = 1;
			obj.m_equipped = false;
			obj.m_dropPrefab = val.m_dropPrefab;
			int stableHashCode3 = StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name);
			zdo.Set(stableHashCode, stableHashCode3, false);
			zdo.Set(stableHashCode2, val.m_variant, false);
			ItemDrop.SaveToZDO(obj, zdo, slot);
			((Humanoid)player).UnequipItem(val, false);
			inventory.RemoveOneItem(val);
			nv.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { slot, stableHashCode3, val.m_variant });
		}
		else
		{
			zdo.Set(stableHashCode, 0, false);
			nv.InvokeRPC(ZNetView.Everybody, "RPC_SetVisualItem", new object[3] { slot, 0, 0 });
		}
		standItem.m_equipped = false;
		inventory.AddItem(standItem);
		((Humanoid)player).EquipItem(standItem, true);
		return true;
	}
}
[HarmonyPatch(typeof(ArmorStand), "UseItem")]
internal static class ArmorStandUseItemSwapPatch
{
	private static bool Prefix(ArmorStand __instance, Switch caller, Humanoid user, ItemData item, ref bool __result)
	{
		if (item != null)
		{
			return true;
		}
		if (ArmorStandSwap.Enabled && ChestRename.BlocksStationUse())
		{
			__result = false;
			return false;
		}
		if (!ArmorStandSwap.TrySwap(__instance, caller, user))
		{
			return true;
		}
		__result = true;
		return false;
	}
}
[HarmonyPatch(typeof(Switch), "GetHoverText")]
internal static class ArmorStandSwapHoverPatch
{
	private static void Postfix(Switch __instance, ref string __result)
	{
		if (!ArmorStandSwap.Enabled || string.IsNullOrEmpty(__result) || Localization.instance == null)
		{
			return;
		}
		ArmorStand componentInParent = ((Component)__instance).GetComponentInParent<ArmorStand>();
		if ((Object)(object)componentInParent == (Object)null)
		{
			return;
		}
		int num = ArmorStandSwap.SlotOf(componentInParent, __instance, occupiedOnly: false);
		string text = Localization.instance.Localize("$piece_itemstand_take");
		if (!string.IsNullOrEmpty(text) && __result.Contains(text))
		{
			string newValue = Loc.T("Swap", "Tauschen");
			if (ArmorStandSwap.IsPresetSlot(componentInParent, num))
			{
				ZNetView val = ArmorStandSwap.ViewOf(componentInParent);
				ItemData val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? ArmorStandSwap.PresetAsItem(val.GetZDO(), num) : null);
				newValue = ((val2 != null) ? (Loc.T("Swap with ", "Tauschen mit ") + Localization.instance.Localize(val2.m_shared.m_name)) : text);
			}
			__result = __result.Replace(text, newValue);
		}
		if (num >= 0)
		{
			__result = __result + "\n[<color=yellow><b>" + StationPullFilter.PromptLabel() + "</b></color>] " + Loc.T("Settings", "Einstellungen");
		}
	}
}
internal static class BuildGrab
{
	private static readonly List<Container> Scratch = new List<Container>(64);

	private static float _lastGrabMsg;

	public static bool GrabHeld()
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.Settings == null)
		{
			return false;
		}
		return KeyUtil.Held(Plugin.Settings.BuildGrabKey.Value);
	}

	public static bool IsHammerPlaceMode(Player player)
	{
		if ((Object)(object)player == (Object)null || !((Character)player).InPlaceMode())
		{
			return false;
		}
		PieceTable buildTool = player.GetBuildTool();
		if ((Object)(object)buildTool == (Object)null)
		{
			return false;
		}
		string text = (((Object)(object)((Component)buildTool).gameObject != (Object)null) ? ((Object)((Component)buildTool).gameObject).name : ((Object)buildTool).name);
		if (string.IsNullOrEmpty(text))
		{
			return false;
		}
		return text.IndexOf("Hammer", StringComparison.OrdinalIgnoreCase) >= 0;
	}

	public static bool ShouldGrab(Player player)
	{
		if (GrabHeld())
		{
			return IsHammerPlaceMode(player);
		}
		return false;
	}

	public static bool TryInterceptPlace(Player player, Piece piece)
	{
		if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null)
		{
			return false;
		}
		if (!ShouldGrab(player))
		{
			return false;
		}
		if (Plugin.Settings == null || !Plugin.Settings.ModEnabled.Value || !Plugin.Settings.CraftEnabled.Value)
		{
			MaybeMsg(player, Loc.T("Craft/build from chests is disabled", "Craft/Bauen aus Truhen ist aus"));
			return true;
		}
		GrabIntoInventory(player, piece);
		return true;
	}

	private static void GrabIntoInventory(Player player, Piece piece)
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		Requirement[] resources = piece.m_resources;
		if (resources == null || resources.Length == 0)
		{
			MaybeMsg(player, Loc.T("Nothing to grab for this piece", "Nichts zum Holen für dieses Piece"));
			return;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return;
		}
		NearbyIndex.Tick();
		bool value = Plugin.Settings.LeaveOneItem.Value;
		float num = Plugin.Settings.CraftReach();
		Vector3 position = ((Component)player).transform.position;
		Scratch.Clear();
		NearbyIndex.CollectNear(position, num, Scratch);
		int num2 = 0;
		int num3 = 0;
		InventoryCountPatches.Skip++;
		try
		{
			Requirement[] array = resources;
			foreach (Requirement val in array)
			{
				if (val?.m_resItem?.m_itemData?.m_shared == null)
				{
					continue;
				}
				int amount = val.GetAmount(1);
				if (amount <= 0)
				{
					continue;
				}
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				int num4 = amount;
				for (int j = 0; j < Scratch.Count; j++)
				{
					Container val2 = Scratch[j];
					if (num4 <= 0)
					{
						break;
					}
					if (!((Object)(object)val2 == (Object)null) && !ChestNames.BlocksCraft(val2) && ContainerFilter.IsPlayerBuiltStorage(val2) && ContainerFilter.PlayerMayUse(val2, position) && !(ContainerFilter.Distance(position, ((Component)val2).transform.position) > num))
					{
						NearbyIndex.EnsureInventory(val2);
						int num5 = TransferService.WithdrawForGrab(val2, name, num4, player, value);
						ActivityLog.Move(Loc.T("Build grab", "Bau-Grab"), ActivityLog.Chest(val2), num5, name, ActivityLog.Bag());
						num4 -= num5;
						num2 += num5;
					}
				}
				if (num4 > 0)
				{
					num3 += num4;
				}
			}
		}
		finally
		{
			InventoryCountPatches.Skip--;
		}
		if (num2 > 0)
		{
			Refs.NotifyChanged(inventory);
		}
		if (num2 <= 0 && num3 > 0)
		{
			MaybeMsg(player, Loc.T("No materials in nearby chests", "Keine Materialien in nahen Truhen"));
		}
		else if (num3 > 0)
		{
			MaybeMsg(player, Loc.T("Grabbed some materials (still short)", "Material geholt (noch zu wenig)"));
		}
		else if (num2 > 0)
		{
			MaybeMsg(player, Loc.T("Grabbed build materials from chests", "Baumaterial aus Truhen geholt"));
		}
		else
		{
			MaybeMsg(player, Loc.T("Could not grab materials (bag full?)", "Kein Material geholt (Tasche voll?)"));
		}
	}

	private static void MaybeMsg(Player player, string text)
	{
		if (!((Object)(object)player == (Object)null) && !string.IsNullOrEmpty(text) && !(Time.time - _lastGrabMsg < 0.35f))
		{
			_lastGrabMsg = Time.time;
			((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
	}
}
[HarmonyPatch(typeof(Player), "TryPlacePiece")]
[HarmonyPriority(800)]
internal static class TryPlacePieceGrabPatch
{
	private static bool Prefix(Player __instance, Piece piece, ref bool __result)
	{
		if (!BuildGrab.TryInterceptPlace(__instance, piece))
		{
			return true;
		}
		__result = false;
		return false;
	}
}
[HarmonyPatch(typeof(Player), "PlacePiece")]
[HarmonyPriority(800)]
internal static class PlacePieceGrabPatch
{
	private static bool Prefix(Player __instance, Piece piece)
	{
		if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && BuildGrab.ShouldGrab(__instance))
		{
			return false;
		}
		return true;
	}
}
internal static class CookingAutoDrop
{
	public const string ZdoKey = "SAC_autoDrop";

	public static readonly int ZdoKeyHash = StringExtensionMethods.GetStableHashCode("SAC_autoDrop");

	private static readonly MethodInfo HaveDoneItem = AccessTools.Method(typeof(CookingStation), "HaveDoneItem", (Type[])null, (Type[])null);

	private static readonly MethodInfo GetSlot = AccessTools.Method(typeof(CookingStation), "GetSlot", (Type[])null, (Type[])null);

	private static readonly MethodInfo SetSlot = AccessTools.Method(typeof(CookingStation), "SetSlot", (Type[])null, (Type[])null);

	private static readonly MethodInfo IsItemDone = AccessTools.Method(typeof(CookingStation), "IsItemDone", (Type[])null, (Type[])null);

	private static readonly Type CookStatusType = AccessTools.Inner(typeof(CookingStation), "Status") ?? AccessTools.TypeByName("CookingStation+Status");

	private static readonly object StatusNotDone = ((CookStatusType != null) ? Enum.ToObject(CookStatusType, 0) : null);

	private static readonly MethodInfo BeeGetHoneyLevel = AccessTools.Method(typeof(Beehive), "GetHoneyLevel", (Type[])null, (Type[])null);

	private static readonly MethodInfo BeeExtract = AccessTools.Method(typeof(Beehive), "Extract", (Type[])null, (Type[])null);

	private static readonly MethodInfo BeeResetLevel = AccessTools.Method(typeof(Beehive), "ResetLevel", (Type[])null, (Type[])null);

	private static readonly MethodInfo SmelterGetConversion = AccessTools.Method(typeof(Smelter), "GetItemConversion", new Type[1] { typeof(string) }, (Type[])null);

	private static readonly MethodInfo FermenterGetStatus = AccessTools.Method(typeof(Fermenter), "GetStatus", (Type[])null, (Type[])null);

	private static readonly MethodInfo FermenterGetConversion = AccessTools.Method(typeof(Fermenter), "GetItemConversion", new Type[1] { typeof(int) }, (Type[])null);

	private const int FermenterStatusReady = 3;

	private static readonly HashSet<Fermenter> FermenterGroundTag = new HashSet<Fermenter>();

	private const float NoticeSlow = 25f;

	public static bool IsOn(ZNetView nv)
	{
		if ((Object)(object)nv == (Object)null || !nv.IsValid() || nv.GetZDO() == null)
		{
			return false;
		}
		return nv.GetZDO().GetInt(ZdoKeyHash, 0) != 0;
	}

	public static bool IsOn(CookingStation station)
	{
		if ((Object)(object)station != (Object)null)
		{
			return IsOn(((Component)station).GetComponent<ZNetView>());
		}
		return false;
	}

	public static bool IsOn(Beehive hive)
	{
		if ((Object)(object)hive != (Object)null)
		{
			return IsOn(((Component)hive).GetComponent<ZNetView>());
		}
		return false;
	}

	public static bool IsOn(Smelter smelter)
	{
		if ((Object)(object)smelter != (Object)null)
		{
			return IsOn(((Component)smelter).GetComponent<ZNetView>());
		}
		return false;
	}

	public static bool IsOn(SapCollector sap)
	{
		if ((Object)(object)sap != (Object)null)
		{
			return IsOn(((Component)sap).GetComponent<ZNetView>());
		}
		return false;
	}

	public static bool IsOn(Fermenter fermenter)
	{
		if ((Object)(object)fermenter != (Object)null)
		{
			return IsOn(((Component)fermenter).GetComponent<ZNetView>());
		}
		return false;
	}

	public static void AppendHover(ref string text, Fermenter fermenter)
	{
		if (!((Object)(object)fermenter == (Object)null))
		{
			AppendHoverLine(ref text, ((Component)fermenter).GetComponent<ZNetView>());
		}
	}

	public static void AppendHover(ref string text, CookingStation station)
	{
		if (!((Object)(object)station == (Object)null))
		{
			AppendHoverLine(ref text, ((Component)station).GetComponent<ZNetView>());
		}
	}

	public static void AppendHover(ref string text, Beehive hive)
	{
		if (!((Object)(object)hive == (Object)null))
		{
			AppendHoverLine(ref text, ((Component)hive).GetComponent<ZNetView>());
		}
	}

	public static void AppendHover(ref string text, SapCollector sap)
	{
		if (!((Object)(object)sap == (Object)null))
		{
			AppendHoverLine(ref text, ((Component)sap).GetComponent<ZNetView>());
		}
	}

	public static void AppendHover(ref string text, Smelter smelter)
	{
		if (!((Object)(object)smelter == (Object)null))
		{
			AppendHoverLine(ref text, ((Component)smelter).GetComponent<ZNetView>());
		}
	}

	private static void AppendHoverLine(ref string text, ZNetView nv)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)nv == (Object)null) && nv.IsValid())
		{
			string text2 = KeyUtil.Format(Plugin.Settings.AutoDropKey.Value);
			if (string.IsNullOrEmpty(text2))
			{
				text2 = "N";
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "";
			}
			text = text + "\n[<color=yellow><b>" + text2 + "</b></color>] " + Loc.T("Auto-store", "Auto-Lagern") + " " + StationAutoFill.OnOffTag(IsOn(nv));
		}
	}

	public static bool TryToggle()
	{
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		if (InventoryGui.IsVisible() || StationFilterMenu.IsOpen || DisplayTypeMenu.IsOpen || DisplayRangeMenu.IsOpen)
		{
			return false;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		CookingStation val = HoveredStation();
		Beehive val2 = (((Object)(object)val == (Object)null) ? HoveredBeehive() : null);
		Smelter val3 = (((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null) ? StationPullFilter.HoveredSmelter() : null);
		Fermenter val4 = (((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null) ? StationPullFilter.HoveredFermenter() : null);
		SapCollector val5 = (((Object)(object)val == (Object)null && (Object)(object)val2 == (Object)null && (Object)(object)val3 == (Object)null && (Object)(object)val4 == (Object)null) ? HoveredSap() : null);
		Component val6 = (Component)(((Object)(object)val != (Object)null) ? val : (((Object)(object)val2 != (Object)null) ? val2 : (((Object)(object)val3 != (Object)null) ? val3 : (((Object)(object)val4 != (Object)null) ? ((object)val4) : ((object)val5)))));
		ZNetView val7 = (((Object)(object)val6 != (Object)null) ? val6.GetComponent<ZNetView>() : null);
		if ((Object)(object)val7 == (Object)null || !val7.IsValid() || val7.GetZDO() == null)
		{
			return false;
		}
		if (!PrivateArea.CheckAccess(val6.transform.position, 0f, false, true))
		{
			((Character)localPlayer).Message((MessageType)2, "$msg_privatezone", 0, (Sprite)null, false);
			return true;
		}
		if (!val7.IsOwner())
		{
			val7.ClaimOwnership();
		}
		bool flag = !IsOn(val7);
		val7.GetZDO().Set(ZdoKeyHash, flag ? 1 : 0, false);
		((Character)localPlayer).Message((MessageType)2, flag ? Loc.T("Auto-store on (chests)", "Auto-Lagern an (Kisten)") : Loc.T("Auto-store off", "Auto-Lagern aus"), 0, (Sprite)null, false);
		ActivityLog.Note(StationOutput.StationLabel(val6), flag ? Loc.T("Auto-store on", "Auto-Lagern an") : Loc.T("Auto-store off", "Auto-Lagern aus"));
		return true;
	}

	public static void TryPopDone(CookingStation station)
	{
		//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)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)station == (Object)null || !IsOn(station))
		{
			return;
		}
		ZNetView component = ((Component)station).GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && !(HaveDoneItem == null) && FastCall.Bool(HaveDoneItem, station))
		{
			StationAutoFill.RequestSoon();
			if (!TryDepositDoneToChest(station, component))
			{
				Vector3 val = DropPoint(station);
				ActivityLog.Note(Loc.T("Auto-store", "Auto-Lagern"), StationOutput.StationLabel((Component)(object)station) + " → " + ActivityLog.Ground() + " (" + Loc.T("no matching chest", "keine passende Kiste") + ")");
				StationOutput.QueueIntakeLinkTag(val, StationLink.Get((Component)(object)station), null);
				component.InvokeRPC("RPC_RemoveDoneItem", new object[2] { val, 1 });
			}
		}
	}

	private static object[] SetSlotArgs(params object[] args)
	{
		ParameterInfo[] parameters = SetSlot.GetParameters();
		if (parameters.Length <= args.Length)
		{
			return args;
		}
		object[] array = new object[parameters.Length];
		Array.Copy(args, array, args.Length);
		for (int i = args.Length; i < parameters.Length; i++)
		{
			array[i] = (parameters[i].HasDefaultValue ? parameters[i].DefaultValue : Type.Missing);
		}
		return array;
	}

	private static bool TryDepositDoneToChest(CookingStation station, ZNetView nv)
	{
		if (GetSlot == null || SetSlot == null || IsItemDone == null || StatusNotDone == null)
		{
			return false;
		}
		if (station.m_slots == null)
		{
			return false;
		}
		for (int i = 0; i < station.m_slots.Length; i++)
		{
			object[] array = new object[5] { i, null, 0f, null, false };
			GetSlot.Invoke(station, array);
			string text = array[1] as string;
			if (!string.IsNullOrEmpty(text) && (bool)IsItemDone.Invoke(station, new object[1] { text }))
			{
				if (!StationOutput.TryDepositNear((Component)(object)station, text, 1, out var label, out var chest))
				{
					StationChestFull.NoteGrill((Component)(object)station, text);
					return false;
				}
				SetSlot.Invoke(station, SetSlotArgs(i, "", 0f, StatusNotDone, false));
				nv.InvokeRPC(ZNetView.Everybody, "RPC_SetSlotVisual", new object[2] { i, "" });
				ActivityLog.ToChest(StationOutput.StationLabel((Component)(object)station), 1, label, chest);
				return true;
			}
		}
		return false;
	}

	internal static void TickHiveNotice(Beehive hive)
	{
		ZNetView component = ((Component)hive).GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && !(BeeGetHoneyLevel == null))
		{
			int amount = 0;
			try
			{
				amount = FastCall.Int(BeeGetHoneyLevel, hive);
			}
			catch
			{
			}
			string productPrefab = (((Object)(object)hive.m_honeyItem != (Object)null) ? ((Object)((Component)hive.m_honeyItem).gameObject).name : "Honey");
			StationChestFull.TickOutput((Component)(object)hive, productPrefab, amount, 25f, clearWhenOk: true);
		}
	}

	internal static void TickSapNotice(SapCollector sap)
	{
		ZNetView component = ((Component)sap).GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner() && component.GetZDO() != null)
		{
			int amount = component.GetZDO().GetInt(ZDOVars.s_level, 0);
			string productPrefab = (((Object)(object)sap.m_spawnItem != (Object)null) ? ((Object)((Component)sap.m_spawnItem).gameObject).name : "Sap");
			StationChestFull.TickOutput((Component)(object)sap, productPrefab, amount, 25f, clearWhenOk: true);
		}
	}

	internal static void TickFermenterNotice(Fermenter fermenter)
	{
		ZNetView component = ((Component)fermenter).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || component.GetZDO() == null || FermenterGetStatus == null || FermenterGetConversion == null)
		{
			return;
		}
		string productPrefab = null;
		int amount = 0;
		try
		{
			if (FastCall.Int(FermenterGetStatus, fermenter) == 3)
			{
				int num = component.GetZDO().GetInt(ZDOVars.s_content, 0);
				object? obj = FermenterGetConversion.Invoke(fermenter, new object[1] { num });
				ItemConversion val = (ItemConversion)((obj is ItemConversion) ? obj : null);
				if (val != null && (Object)(object)val.m_to != (Object)null && val.m_producedItems > 0)
				{
					productPrefab = ((Object)((Component)val.m_to).gameObject).name;
					amount = val.m_producedItems * Mathf.Max(1, FermenterBatch.Count(fermenter));
				}
			}
		}
		catch
		{
			return;
		}
		StationChestFull.TickOutput((Component)(object)fermenter, productPrefab, amount, 25f, clearWhenOk: true);
	}

	public static void TryExtractHoney(Beehive hive)
	{
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)hive == (Object)null || !IsOn(hive))
		{
			return;
		}
		ZNetView component = ((Component)hive).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || BeeGetHoneyLevel == null)
		{
			return;
		}
		int num;
		try
		{
			num = FastCall.Int(BeeGetHoneyLevel, hive);
		}
		catch
		{
			return;
		}
		if (num <= 0)
		{
			return;
		}
		StationAutoFill.RequestSoon();
		string text = (((Object)(object)hive.m_honeyItem != (Object)null) ? ((Object)((Component)hive.m_honeyItem).gameObject).name : "Honey");
		if (StationOutput.TryDepositNear((Component)(object)hive, text, num, out var label, out var chest))
		{
			if (BeeResetLevel != null)
			{
				BeeResetLevel.Invoke(hive, null);
			}
			else if (component.GetZDO() != null)
			{
				component.GetZDO().Set(ZDOVars.s_level, 0, false);
			}
			ActivityLog.ToChest(StationOutput.StationLabel((Component)(object)hive), num, label, chest);
			return;
		}
		if (BeeExtract != null)
		{
			try
			{
				BeeExtract.Invoke(hive, null);
			}
			catch
			{
			}
		}
		ActivityLog.Move(Loc.T("Auto-store", "Auto-Lagern"), StationOutput.StationLabel((Component)(object)hive), num, text, ActivityLog.Ground());
		StationOutput.QueueIntakeLinkTag(((Component)hive).transform.position + Vector3.up * 0.5f, StationLink.Get((Component)(object)hive), text);
	}

	public static void TryExtractSap(SapCollector sap)
	{
		if ((Object)(object)sap == (Object)null || !IsOn(sap))
		{
			return;
		}
		ZNetView component = ((Component)sap).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || component.GetZDO() == null)
		{
			return;
		}
		int num = component.GetZDO().GetInt(ZDOVars.s_level, 0);
		if (num > 0)
		{
			string prefabOrToken = (((Object)(object)sap.m_spawnItem != (Object)null) ? ((Object)((Component)sap.m_spawnItem).gameObject).name : "Sap");
			if (StationOutput.TryDepositNear((Component)(object)sap, prefabOrToken, num, out var label, out var chest))
			{
				component.GetZDO().Set(ZDOVars.s_level, 0, false);
				component.InvokeRPC(ZNetView.Everybody, "RPC_UpdateEffects", Array.Empty<object>());
				ActivityLog.ToChest(StationOutput.StationLabel((Component)(object)sap), num, label, chest);
			}
		}
	}

	public static void TryTapFermenter(Fermenter fermenter)
	{
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)fermenter == (Object)null || !IsOn(fermenter))
		{
			return;
		}
		ZNetView component = ((Component)fermenter).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner() || component.GetZDO() == null || FermenterGetStatus == null || FermenterGetConversion == null)
		{
			return;
		}
		int num;
		try
		{
			num = FastCall.Int(FermenterGetStatus, fermenter);
		}
		catch
		{
			return;
		}
		if (num != 3)
		{
			return;
		}
		int num2 = component.GetZDO().GetInt(ZDOVars.s_content, 0);
		object? obj2 = FermenterGetConversion.Invoke(fermenter, new object[1] { num2 });
		ItemConversion val = (ItemConversion)((obj2 is ItemConversion) ? obj2 : null);
		if (val == null || (Object)(object)val.m_to == (Object)null || val.m_producedItems <= 0)
		{
			return;
		}
		string name = ((Object)((Component)val.m_to).gameObject).name;
		int amount = val.m_producedItems * Mathf.Max(1, FermenterBatch.Count(fermenter));
		StationAutoFill.RequestSoon();
		if (StationOutput.TryDepositNear((Component)(object)fermenter, name, amount, out var label, out var chest))
		{
			component.GetZDO().Set(ZDOVars.s_content, 0, false);
			component.GetZDO().Set(ZDOVars.s_startTime, 0L);
			component.GetZDO().Set(ZDOVars.s_cheatedQueued, false);
			FermenterBatch.ClearAfterDeposit(fermenter);
			if (fermenter.m_tapEffects != null)
			{
				fermenter.m_tapEffects.Create(((Component)fermenter).transform.position, ((Component)fermenter).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
			}
			ActivityLog.ToChest(StationOutput.StationLabel((Component)(object)fermenter), amount, label, chest);
		}
		else
		{
			ActivityLog.Move(Loc.T("Auto-store", "Auto-Lagern"), StationOutput.StationLabel((Component)(object)fermenter), amount, name, ActivityLog.Ground());
			FermenterGroundTag.Add(fermenter);
			component.InvokeRPC("RPC_Tap", Array.Empty<object>());
		}
	}

	internal static void TagFermenterDrops(Fermenter fermenter)
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)fermenter == (Object)null) && FermenterGroundTag.Remove(fermenter))
		{
			Transform outputPoint = fermenter.m_outputPoint;
			StationOutput.QueueIntakeLinkTag(((Object)(object)outputPoint != (Object)null) ? outputPoint.position : (((Component)fermenter).transform.position + Vector3.up * 0.5f), StationLink.Get((Component)(object)fermenter), null);
		}
	}

	private static Vector3 DropPoint(CookingStation station)
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		Transform spawnPoint = station.m_spawnPoint;
		if ((Object)(object)spawnPoint != (Object)null)
		{
			return spawnPoint.position;
		}
		return ((Component)station).transform.position + Vector3.up * 0.5f;
	}

	private static CookingStation HoveredStation()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return null;
		}
		GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
		if ((Object)(object)hoverObject == (Object)null)
		{
			return null;
		}
		return hoverObject.GetComponentInParent<CookingStation>();
	}

	private static SapCollector HoveredSap()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return null;
		}
		GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
		if ((Object)(object)hoverObject == (Object)null)
		{
			return null;
		}
		return hoverObject.GetComponentInParent<SapCollector>();
	}

	private static Beehive HoveredBeehive()
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return null;
		}
		GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject();
		if ((Object)(object)hoverObject == (Object)null)
		{
			return null;
		}
		return hoverObject.GetComponentInParent<Beehive>();
	}

	internal static bool TryGetSmelterOutputPrefab(Smelter smelter, string ore, out string prefabName)
	{
		prefabName = null;
		if ((Object)(object)smelter == (Object)null || ore == null || SmelterGetConversion == null)
		{
			return false;
		}
		object obj = SmelterGetConversion.Invoke(smelter, new object[1] { ore });
		if (obj == null)
		{
			return false;
		}
		FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), "m_to");
		if (fieldInfo == null)
		{
			return false;
		}
		object? value = fieldInfo.GetValue(obj);
		ItemDrop val = (ItemDrop)((value is ItemDrop) ? value : null);
		if ((Object)(object)val == (Object)null)
		{
			return false;
		}
		prefabName = ((Object)((Component)val).gameObject).name;
		return true;
	}
}
[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
internal static class CookingAutoDropUpdatePatch
{
	private static void Postfix(CookingStation __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && CookingAutoDrop.IsOn(__instance))
		{
			StationChestFull.TickGrill(__instance);
			CookingAutoDrop.TryPopDone(__instance);
		}
	}
}
[HarmonyPatch(typeof(Beehive), "UpdateBees")]
internal static class BeehiveAutoDropUpdatePatch
{
	private static void Postfix(Beehive __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && CookingAutoDrop.IsOn(__instance))
		{
			CookingAutoDrop.TickHiveNotice(__instance);
			CookingAutoDrop.TryExtractHoney(__instance);
		}
	}
}
[HarmonyPatch(typeof(SapCollector), "UpdateTick")]
internal static class SapCollectorAutoDropUpdatePatch
{
	private static void Postfix(SapCollector __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && CookingAutoDrop.IsOn(__instance))
		{
			CookingAutoDrop.TickSapNotice(__instance);
			CookingAutoDrop.TryExtractSap(__instance);
		}
	}
}
[HarmonyPatch(typeof(SapCollector), "GetHoverText")]
internal static class SapCollectorAutoDropHoverPatch
{
	private static void Postfix(SapCollector __instance, ref string __result)
	{
		CookingAutoDrop.AppendHover(ref __result, __instance);
	}
}
[HarmonyPatch(typeof(Fermenter), "SlowUpdate")]
internal static class FermenterAutoDropUpdatePatch
{
	private static void Postfix(Fermenter __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && CookingAutoDrop.IsOn(__instance))
		{
			CookingAutoDrop.TickFermenterNotice(__instance);
			CookingAutoDrop.TryTapFermenter(__instance);
		}
	}
}
[HarmonyPatch(typeof(Fermenter), "DelayedTap")]
internal static class FermenterAutoDropTagPatch
{
	private static void Postfix(Fermenter __instance)
	{
		CookingAutoDrop.TagFermenterDrops(__instance);
	}
}
[HarmonyPatch(typeof(Beehive), "GetHoverText")]
internal static class BeehiveAutoDropHoverPatch
{
	private static void Postfix(Beehive __instance, ref string __result)
	{
		CookingAutoDrop.AppendHover(ref __result, __instance);
	}
}
[HarmonyPatch(typeof(Smelter), "Spawn")]
internal static class SmelterAutoDropDepositPatch
{
	private static int _tagLink = -1;

	private static Vector3 _tagPos;

	private static string _tagPrefab;

	private static bool Prefix(Smelter __instance, string ore, int stack)
	{
		//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_008d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		_tagLink = -1;
		if ((Object)(object)__instance == (Object)null || stack <= 0 || ore == null)
		{
			return true;
		}
		if (!CookingAutoDrop.IsOn(__instance))
		{
			return true;
		}
		ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
		if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
		{
			return true;
		}
		if (!CookingAutoDrop.TryGetSmelterOutputPrefab(__instance, ore, out var prefabName))
		{
			return true;
		}
		if (!StationOutput.TryDepositNear((Component)(object)__instance, prefabName, stack, out var label, out var chest))
		{
			_tagLink = StationLink.Get((Component)(object)__instance);
			_tagPrefab = prefabName;
			Transform outputPoint = __instance.m_outputPoint;
			_tagPos = (((Object)(object)outputPoint != (Object)null) ? outputPoint.position : (((Component)__instance).transform.position + Vector3.up * 0.5f));
			ActivityLog.Move(Loc.T("Auto-store", "Auto-Lagern"), StationOutput.StationLabel((Component)(object)__instance), stack, prefabName, ActivityLog.Ground());
			return true;
		}
		if (__instance.m_produceEffects != null)
		{
			__instance.m_produceEffects.Create(((Component)__instance).transform.position, ((Component)__instance).transform.rotation, (Transform)null, 1f, -1, default(ZDOID));
		}
		ActivityLog.ToChest(StationOutput.StationLabel((Component)(object)__instance), stack, label, chest);
		return false;
	}

	private static void Postfix(Smelter __instance, string ore, int stack)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		if (_tagLink >= 0)
		{
			StationOutput.QueueIntakeLinkTag(_tagPos, _tagLink, _tagPrefab);
			_tagLink = -1;
		}
	}
}
internal static class EpicLootBridge
{
	private const string EpicLootGuid = "randyknapp.mods.epicloot";

	private static readonly List<ItemData> ItemScratch = new List<ItemData>(64);

	private static bool _tried;

	private static bool _registered;

	public static void TryRegister()
	{
		if (_tried)
		{
			return;
		}
		_tried = true;
		if (!Chainloader.PluginInfos.ContainsKey("randyknapp.mods.epicloot"))
		{
			return;
		}
		try
		{
			Type type = FindApiType();
			if (type == null)
			{
				Plugin.Log.LogDebug((object)"Epic Loot present but API type not found.");
				return;
			}
			MethodInfo method = type.GetMethod("RegisterInventoryProvider", BindingFlags.Static | BindingFlags.Public, null, new Type[5]
			{
				typeof(string),
				typeof(Func<List<ItemData>>),
				typeof(Func<string, int>),
				typeof(Func<string, int, int>),
				typeof(Func<ItemData, int, int>)
			}, null);
			if (method == null)
			{
				Plugin.Log.LogWarning((object)"Epic Loot found, but RegisterInventoryProvider is missing. Update Epic Loot.");
				return;
			}
			object obj = method.Invoke(null, new object[5]
			{
				"com.morda.storeandcraft",
				new Func<List<ItemData>>(GetNearbyItems),
				new Func<string, int>(CountNearbyItem),
				new Func<string, int, int>(RemoveNearbyItem),
				new Func<ItemData, int, int>(RemoveNearbyExactItem)
			});
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			_registered = (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			if (_registered)
			{
				Plugin.Log.LogDebug((object)"Registered chest inventory provider with Epic Loot.");
			}
			else
			{
				Plugin.Log.LogDebug((object)"Epic Loot RegisterInventoryProvider returned false.");
			}
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Epic Loot inventory provider failed: " + ex.Message));
		}
	}

	public static void TryUnregister()
	{
		if (_registered)
		{
			try
			{
				(FindApiType()?.GetMethod("UnregisterInventoryProvider", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null))?.Invoke(null, new object[1] { "com.morda.storeandcraft" });
			}
			catch
			{
			}
			_registered = false;
		}
	}

	private static Type FindApiType()
	{
		Type type = Type.GetType("EpicLoot.API, EpicLoot", throwOnError: false);
		if (type != null)
		{
			return type;
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			if (assembly == null)
			{
				continue;
			}
			string name = assembly.GetName().Name;
			if (!(name != "EpicLoot") || !(name != "EpicLootAPI"))
			{
				Type type2 = assembly.GetType("EpicLoot.API");
				if (type2 != null)
				{
					return type2;
				}
			}
		}
		return null;
	}

	private static bool Ready()
	{
		return StagingPull.Active;
	}

	private static List<ItemData> GetNearbyItems()
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: Unknown result type (might be due to invalid IL or missing references)
		ItemScratch.Clear();
		if (!Ready())
		{
			return ItemScratch;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return ItemScratch;
		}
		float num = StationFeed.ActivePullRange();
		if (num <= 0f)
		{
			return ItemScratch;
		}
		Vector3 position = ((Component)localPlayer).transform.position;
		foreach (Container item in NearbyIndex.Current)
		{
			if ((Object)(object)item == (Object)null || ChestNames.BlocksCraft(item) || ContainerFilter.Distance(position, ((Component)item).transform.position) > num)
			{
				continue;
			}
			NearbyIndex.EnsureInventory(item);
			Inventory inventory = item.GetInventory();
			if (inventory == null)
			{
				continue;
			}
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem?.m_shared != null && allItem.m_stack > 0)
				{
					ItemScratch.Add(allItem);
				}
			}
		}
		return ItemScratch;
	}

	private static int CountNearbyItem(string sharedName)
	{
		//IL_0028: Unknown result type (might be due to invalid IL or missing references)
		if (!Ready() || string.IsNullOrEmpty(sharedName))
		{
			return 0;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return 0;
		}
		return NearbyIndex.CountItem(((Component)localPlayer).transform.position, 0f, sharedName, leaveOne: false);
	}

	private static int RemoveNearbyItem(string sharedName, int amount)
	{
		if (!Ready() || amount <= 0 || string.IsNullOrEmpty(sharedName))
		{
			return 0;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return 0;
		}
		return ConsumeFromChestsNoLeaveOne(localPlayer, sharedName, amount);
	}

	private static int ConsumeFromChestsNoLeaveOne(Player player, string shared, int amount)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		NearbyIndex.Tick();
		float num = StationFeed.ActivePullRange();
		Vector3 position = ((Component)player).transform.position;
		int num2 = amount;
		int num3 = 0;
		foreach (Container item in NearbyIndex.Current)
		{
			if (num2 <= 0)
			{
				break;
			}
			if (!((Object)(object)item == (Object)null) && !ChestNames.BlocksCraft(item) && !(ContainerFilter.Distance(position, ((Component)item).transform.position) > num))
			{
				int num4 = TransferService.Consume(item, shared, num2, leaveOne: false);
				if (num4 > 0)
				{
					ActivityLog.Move("Epic Loot", ActivityLog.Chest(item), num4, shared, ActivityLog.Used());
					num3 += num4;
					num2 -= num4;
				}
			}
		}
		return num3;
	}

	private static int RemoveNearbyExactItem(ItemData item, int amount)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_005e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		if (!Ready() || item == null || amount <= 0)
		{
			return 0;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return 0;
		}
		float num = StationFeed.ActivePullRange();
		Vector3 position = ((Component)localPlayer).transform.position;
		foreach (Container item2 in NearbyIndex.Current)
		{
			if (!((Object)(object)item2 == (Object)null) && !ChestNames.BlocksCraft(item2) && !(ContainerFilter.Distance(position, ((Component)item2).transform.position) > num))
			{
				Inventory inventory = item2.GetInventory();
				if (inventory != null && inventory.ContainsItem(item))
				{
					int num2 = TransferService.ConsumeExact(item2, item, amount);
					ActivityLog.Move("Epic Loot", ActivityLog.Chest(item2), num2, (item.m_shared != null) ? item.m_shared.m_name : null, ActivityLog.Used());
					return num2;
				}
			}
		}
		return 0;
	}
}
internal static class EpicLootCompat
{
	public static bool IsEnchantingPiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return false;
		}
		if (!NameLooksEnchanting(((Object)(object)((Component)piece).gameObject != (Object)null) ? ((Object)((Component)piece).gameObject).name : null))
		{
			return NameLooksEnchanting(piece.m_name);
		}
		return true;
	}

	public static bool IsEnchantingStation(CraftingStation station)
	{
		if ((Object)(object)station == (Object)null)
		{
			return false;
		}
		if (NameLooksEnchanting(((Object)(object)((Component)station).gameObject != (Object)null) ? ((Object)((Component)station).gameObject).name : null))
		{
			return true;
		}
		return NameLooksEnchanting(station.m_name);
	}

	public static bool NameLooksEnchanting(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return false;
		}
		string text = raw.ToLowerInvariant();
		if (!text.Contains("enchant") && !text.Contains("augment"))
		{
			return text.Contains("epicloot");
		}
		return true;
	}
}
internal static class FermenterBatch
{
	internal const string ZdoKey = "SAC_fermBatch";

	internal static readonly int ZdoKeyHash = StringExtensionMethods.GetStableHashCode("SAC_fermBatch");

	internal const string RpcAdd = "SAC_FermAdd";

	internal const float AddWindowSeconds = 60f;

	private const int StatusFermenting = 1;

	private const int StatusReady = 3;

	private static readonly MethodInfo GetStatusM = AccessTools.Method(typeof(Fermenter), "GetStatus", (Type[])null, (Type[])null);

	private static readonly MethodInfo GetTimeM = AccessTools.Method(typeof(Fermenter), "GetFermentationTime", (Type[])null, (Type[])null);

	private static readonly MethodInfo GetConversionM = AccessTools.Method(typeof(Fermenter), "GetItemConversion", new Type[1] { typeof(int) }, (Type[])null);

	private static readonly FieldInfo DelayedItemF = AccessTools.Field(typeof(Fermenter), "m_delayedTapItem");

	private static readonly FieldInfo DelayedCheatedF = AccessTools.Field(typeof(Fermenter), "m_delayedTapItemCheated");

	private static readonly Dictionary<int, int> PendingTap = new Dictionary<int, int>();

	internal static int MaxBatch()
	{
		if (Plugin.Settings == null)
		{
			return 1;
		}
		return Mathf.Clamp(Mathf.RoundToInt(Plugin.Settings.FermenterBatch.Value), 1, Mathf.RoundToInt(50f));
	}

	internal static int Count(Fermenter f)
	{
		ZDO val = Zdo(f);
		if (val == null || val.GetInt(ZDOVars.s_content, 0) == 0)
		{
			return 0;
		}
		return Mathf.Max(1, val.GetInt(ZdoKeyHash, 1));
	}

	internal static int ContentHash(Fermenter f)
	{
		ZDO val = Zdo(f);
		if (val == null)
		{
			return 0;
		}
		return val.GetInt(ZDOVars.s_content, 0);
	}

	internal static string ContentShared(Fermenter f)
	{
		int num = ContentHash(f);
		GameObject val = ((num != 0 && (Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(num) : null);
		ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
		if (!((Object)(object)val2 != (Object)null) || val2.m_itemData?.m_shared == null)
		{
			return null;
		}
		return val2.m_itemData.m_shared.m_name;
	}

	internal static bool CanAddMore(Fermenter f)
	{
		if ((Object)(object)f == (Object)null || MaxBatch() <= 1 || GetStatusM == null || GetTimeM == null)
		{
			return false;
		}
		try
		{
			if (FastCall.Int(GetStatusM, f) != 1)
			{
				return false;
			}
			double num = FastCall.Double(GetTimeM, f);
			if (num < 0.0 || num > 60.0)
			{
				return false;
			}
		}
		catch
		{
			return false;
		}
		return Count(f) < MaxBatch();
	}

	internal static bool TryAddFrom(Fermenter f, Humanoid user, ItemData item)
	{
		if ((Object)(object)f == (Object)null || (Object)(object)user == (Object)null || !CanAddMore(f))
		{
			return false;
		}
		int num = ContentHash(f);
		Inventory inventory = user.GetInventory();
		if (inventory == null)
		{
			return false;
		}
		if (item == null)
		{
			item = FindMatching(inventory, num);
		}
		if (item == null || (Object)(object)item.m_dropPrefab == (Object)null || StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name) != num)
		{
			return false;
		}
		if (!inventory.RemoveOneItem(item))
		{
			return false;
		}
		((Component)f).GetComponent<ZNetView>().InvokeRPC("SAC_FermAdd", new object[1] { num });
		return true;
	}

	internal static void AddCounted(Fermenter f, int nameHash, int n)
	{
		ZNetView val = (((Object)(object)f != (Object)null) ? ((Component)f).GetComponent<ZNetView>() : null);
		if (!((Object)(object)val == (Object)null) && val.IsValid())
		{
			for (int i = 0; i < n; i++)
			{
				val.InvokeRPC("SAC_FermAdd", new object[1] { nameHash });
			}
		}
	}

	private static ItemData FindMatching(Inventory inv, int content)
	{
		List<ItemData> allItems = inv.GetAllItems();
		for (int i = 0; i < allItems.Count; i++)
		{
			ItemData val = allItems[i];
			if ((Object)(object)val?.m_dropPrefab != (Object)null && StringExtensionMethods.GetStableHashCode(((Object)val.m_dropPrefab).name) == content)
			{
				return val;
			}
		}
		return null;
	}

	private static ZDO Zdo(Fermenter f)
	{
		ZNetView val = (((Object)(object)f != (Object)null) ? ((Component)f).GetComponent<ZNetView>() : null);
		if (!((Object)(object)val != (Object)null) || !val.IsValid())
		{
			return null;
		}
		return val.GetZDO();
	}

	internal static void Register(Fermenter f)
	{
		ZNetView val = (((Object)(object)f != (Object)null) ? ((Component)f).GetComponent<ZNetView>() : null);
		if (!((Object)(object)val == (Object)null) && val.GetZDO() != null)
		{
			val.Register<int>("SAC_FermAdd", (Action<long, int>)delegate(long sender, int hash)
			{
				RPC_Add(f, hash);
			});
		}
	}

	private static void RPC_Add(Fermenter f, int nameHash)
	{
		//IL_0073: Unknown result type (might be due to invalid IL or missi