Decompiled source of NearbyCraftingForked v1.5.3

NearbyCraftingForked.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NearbyCraftingForked")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.5.3.0")]
[assembly: AssemblyInformationalVersion("1.5.3+7fe9097ad78a24c415e18461ad353df0bdf1e4f1")]
[assembly: AssemblyProduct("NearbyCraftingForked")]
[assembly: AssemblyTitle("NearbyCraftingForked")]
[assembly: AssemblyVersion("1.5.3.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NearbyCraftingForked
{
	[BepInPlugin("com.sonicdm.valheim.nearbycraftingforked", "Nearby Crafting Forked", "1.5.3")]
	public sealed class NearbyCraftingForkedPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.sonicdm.valheim.nearbycraftingforked";

		public const string PluginName = "Nearby Crafting Forked";

		public const string PluginVersion = "1.5.3";

		internal static ConfigEntry<float> Range;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> EnableBuilding;

		internal static ConfigEntry<bool> IgnoreMovingContainers;

		internal static ConfigEntry<bool> IgnoreObliterators;

		internal static ConfigEntry<bool> RequirePlayerPlacedContainer;

		internal static ConfigEntry<bool> FixRequirementIndicator;

		internal static ConfigEntry<bool> BalrondCompatibility;

		internal static ConfigEntry<bool> DebugLogging;

		internal static ConfigEntry<bool> DebugContainerDetails;

		internal static ConfigEntry<bool> EnableMassDeposit;

		internal static ConfigEntry<KeyboardShortcut> MassDepositHotkey;

		internal static ConfigEntry<bool> QuickDepositHighlightChests;

		internal static ConfigEntry<string> QuickDepositHighlightColor;

		internal static ConfigEntry<float> QuickDepositHighlightAlpha;

		internal static ConfigEntry<float> QuickDepositHighlightDurationSeconds;

		internal static ConfigEntry<KeyboardShortcut> ReloadConfigHotkey;

		internal static ConfigEntry<bool> AutoReloadConfig;

		internal static ConfigEntry<bool> StationFuelEnabled;

		internal static ConfigEntry<bool> EnableOreFromChests;

		internal static ConfigEntry<bool> ItemLocateEnabled;

		internal static ConfigEntry<int> ItemLocateMaxHighlights;

		internal static ConfigEntry<float> ItemLocateDurationSeconds;

		internal static ConfigEntry<string> ItemLocateGlowColor;

		internal static ConfigEntry<float> ItemLocateGlowAlpha;

		internal static ConfigEntry<bool> QuickDepositExcludeConsumables;

		internal static ConfigEntry<bool> QuickDepositExcludeAmmo;

		internal static ConfigEntry<bool> QuickDepositExcludeEquipment;

		internal static ConfigEntry<bool> QuickDepositExcludeUtility;

		internal static ConfigEntry<string> QuickDepositExcludedItemTypes;

		internal static ConfigEntry<string> QuickDepositExcludedItems;

		internal static ConfigEntry<string> QuickDepositAllowedItems;

		internal static ManualLogSource ModLogger;

		private Harmony? _harmony;

		private DateTime _configLastWriteUtc;

		private float _configWatchNextCheck;

		private DateTime _configPendingWriteUtc;

		private float _configPendingSince = -1f;

		internal static bool DebugEnabled
		{
			get
			{
				if (DebugLogging != null)
				{
					return DebugLogging.Value;
				}
				return false;
			}
		}

		internal static bool ContainerDebugEnabled
		{
			get
			{
				if (DebugEnabled && DebugContainerDetails != null)
				{
					return DebugContainerDetails.Value;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Expected O, but got Unknown
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Expected O, but got Unknown
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Expected O, but got Unknown
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Expected O, but got Unknown
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Expected O, but got Unknown
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0446: Expected O, but got Unknown
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Expected O, but got Unknown
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0488: Expected O, but got Unknown
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e9: Expected O, but got Unknown
			//IL_04e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Expected O, but got Unknown
			//IL_05ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f8: Expected O, but got Unknown
			//IL_0713: Unknown result type (might be due to invalid IL or missing references)
			ModLogger = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable Nearby Crafting.");
			EnableBuilding = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableBuilding", true, "Allow building pieces to use materials from nearby containers.");
			Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ContainerRange", 20f, new ConfigDescription("Maximum distance in metres from the player to a container.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
			IgnoreMovingContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreMovingContainers", true, "Ignore ships, and ignore carts that are currently attached or in use. Parked/idle carts stay usable for craft, build, deposit, fuel, and locate.");
			IgnoreObliterators = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "IgnoreObliterators", true, "Ignore Obliterators (Incinerator). Prevents Quick Deposit and nearby crafting/building from using them.");
			RequirePlayerPlacedContainer = ((BaseUnityPlugin)this).Config.Bind<bool>("Containers", "RequirePlayerPlacedContainer", true, "Only use containers attached to a Piece (normally player-built storage), avoiding most world loot chests.");
			FixRequirementIndicator = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "FixRequirementIndicator", true, "Treat nearby-container materials as available when coloring crafting requirement indicators.");
			BalrondCompatibility = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "BalrondConstructions", true, "Recognize storage prefabs where Container and Piece are siblings under the same prefab root (used by BalrondConstructions and some other build mods).");
			DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLogging", false, "Write Nearby Crafting diagnostic information to BepInEx LogOutput.log.");
			DebugContainerDetails = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugContainerDetails", false, "When DebugLogging is enabled, include per-container cache/scan details. This can be noisy.");
			EnableMassDeposit = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit", "Enabled", true, "Enable the nearby mass quick-deposit hotkey.");
			MassDepositHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Quick Deposit", "Hotkey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Hotkey used to quick-deposit matching inventory stacks into all eligible nearby containers. Default: F6.");
			QuickDepositHighlightChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit", "HighlightChests", false, "Glow chests and parked carts that received items from Quick Deposit. Off by default. Color, opacity, and duration are HighlightColor / HighlightAlpha / HighlightDurationSeconds. Clear with 'nearby clear'.");
			QuickDepositHighlightColor = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit", "HighlightColor", "#248038", "Glow color as hex (#248038) or RGB (36,128,56 or 0.14,0.50,0.22). rgb()/rgba() pastes work. Use HighlightAlpha for opacity.");
			QuickDepositHighlightAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Quick Deposit", "HighlightAlpha", 1f, new ConfigDescription("Opacity of Quick Deposit chest glows. 0 is invisible, 1 is full intensity.", (AcceptableValueBase)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			QuickDepositHighlightDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Quick Deposit", "HighlightDurationSeconds", 15f, new ConfigDescription("How long Quick Deposit chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(1f, 120f), Array.Empty<object>()));
			ReloadConfigHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ReloadConfigHotkey", KeyboardShortcut.Empty, "Optional hotkey to force-reload this mod's config from disk. Unset by default.");
			AutoReloadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoReloadConfig", true, "Automatically reload this mod's config when the .cfg file changes on disk (edit in r2modman/Notepad, save, and it applies in-game).");
			QuickDepositExcludeConsumables = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeConsumables", true, "Keep consumables such as food, meads and potions in the player inventory.");
			QuickDepositExcludeAmmo = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeAmmo", true, "Keep ammunition such as arrows and bolts in the player inventory.");
			QuickDepositExcludeEquipment = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeEquipment", true, "Keep weapons, armor, shields, tools, torches and other equipment in the player inventory.");
			QuickDepositExcludeUtility = ((BaseUnityPlugin)this).Config.Bind<bool>("Quick Deposit - Exclusions", "ExcludeUtility", true, "Keep Utility item types in the player inventory.");
			QuickDepositExcludedItemTypes = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "ExcludedItemTypes", "", "Additional ItemType names to exclude, comma-separated. Matching is case-insensitive. Example: Trophy,Misc");
			QuickDepositExcludedItems = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "ExcludedItems", "", "Prefab, shared, or localized item names to exclude, comma-separated. Case-insensitive. * wildcards allowed. A leading * matches the display name and the first prefab word only — not descriptions or later words in a compound prefab (so *Berr* will not match Oatmeal). Example: Coins,DragonEgg,Oatmeal");
			QuickDepositAllowedItems = ((BaseUnityPlugin)this).Config.Bind<string>("Quick Deposit - Exclusions", "AllowedItems", "", "Exceptions to exclusions: these items still quick-deposit even if their ItemType is excluded. Prefab, shared, or localized names, case-insensitive, * wildcards allowed. A leading * matches display name / first prefab word only (so *Berr* deposits berries, not Oatmeal). Example: Mushroom*,Honey,*Berr*");
			StationFuelEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Station Fuel", "Enabled", true, "Pull fuel (and smelter ore) from nearby eligible containers when interacting with smelters, kilns, fires, torches, braziers, and similar stations.");
			EnableOreFromChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Station Fuel", "EnableOreFromChests", true, "When Station Fuel is enabled, also pull smelter/kiln/blast-furnace cookable inputs (ore/scrap) from nearby containers.");
			ItemLocateEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Item Locate", "Enabled", true, "Enable the 'nearby' console/chat command to glow eligible chests and parked carts that contain an item.");
			ItemLocateMaxHighlights = ((BaseUnityPlugin)this).Config.Bind<int>("Item Locate", "MaxHighlights", 10, new ConfigDescription("Maximum chests/carts to glow (nearest first; farther matches are culled).", (AcceptableValueBase)new AcceptableValueRange<int>(1, 50), Array.Empty<object>()));
			ItemLocateDurationSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "DurationSeconds", 15f, new ConfigDescription("How long chest glows last before auto-clear.", (AcceptableValueBase)new AcceptableValueRange<float>(3f, 120f), Array.Empty<object>()));
			ItemLocateGlowColor = ((BaseUnityPlugin)this).Config.Bind<string>("Item Locate", "GlowColor", "#8C731A", "Glow color as hex (#8C731A) or RGB (140,115,26 or 0.55,0.45,0.10). rgb()/rgba() pastes work. Use GlowAlpha for opacity.");
			ItemLocateGlowAlpha = ((BaseUnityPlugin)this).Config.Bind<float>("Item Locate", "GlowAlpha", 1f, new ConfigDescription("Opacity of item-locate chest glows. 0 is invisible, 1 is full intensity.", (AcceptableValueBase)new AcceptableValueRange<float>(0.05f, 1f), Array.Empty<object>()));
			Range.SettingChanged += OnContainerSettingChanged;
			IgnoreMovingContainers.SettingChanged += OnContainerSettingChanged;
			IgnoreObliterators.SettingChanged += OnContainerSettingChanged;
			RequirePlayerPlacedContainer.SettingChanged += OnContainerSettingChanged;
			BalrondCompatibility.SettingChanged += OnContainerSettingChanged;
			Enabled.SettingChanged += OnEnabledChanged;
			_configLastWriteUtc = GetConfigWriteTimeUtc();
			_configWatchNextCheck = 0f;
			_harmony = new Harmony("com.sonicdm.valheim.nearbycraftingforked");
			try
			{
				_harmony.PatchAll();
				ItemLocate.RegisterCommand();
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Nearby Crafting Forked" + " 1.5.3 loaded."));
				if (DebugEnabled)
				{
					Debug($"Config: Enabled={Enabled.Value}, EnableBuilding={EnableBuilding.Value}, Range={Range.Value:0.##}m, " + $"RequirePlayerPlacedContainer={RequirePlayerPlacedContainer.Value}, " + $"IgnoreMovingContainers={IgnoreMovingContainers.Value}, IgnoreObliterators={IgnoreObliterators.Value}, " + $"FixRequirementIndicator={FixRequirementIndicator.Value}, " + $"BalrondCompatibility={BalrondCompatibility.Value}, " + $"EnableMassDeposit={EnableMassDeposit.Value}, MassDepositHotkey={MassDepositHotkey.Value}, " + $"QDHighlight={QuickDepositHighlightChests.Value}, " + $"StationFuel={StationFuelEnabled.Value}, OreFromChests={EnableOreFromChests.Value}, " + $"ItemLocate={ItemLocateEnabled.Value}, " + $"DebugContainerDetails={DebugContainerDetails.Value}");
				}
			}
			catch (Exception ex)
			{
				try
				{
					_harmony.UnpatchSelf();
				}
				catch
				{
				}
				Enabled.Value = false;
				((BaseUnityPlugin)this).Logger.LogError((object)("Nearby Crafting Forked" + " failed to apply its Harmony patches and has been disabled."));
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private static void OnContainerSettingChanged(object? sender, EventArgs e)
		{
			NearbyContainers.InvalidateAll();
			if (DebugEnabled)
			{
				Debug("Container-related configuration changed; caches invalidated.");
			}
		}

		private static void OnEnabledChanged(object? sender, EventArgs e)
		{
			ResetRuntimeState();
		}

		internal static void ResetRuntimeState()
		{
			NearbyContainers.InvalidateAll();
			RequirementUiCache.Clear();
			BuildingPlacementState.Clear();
			RecipeRequirementContext.Clear();
			RecipeConsumptionRules.Clear();
			CraftingContext.Clear();
			ItemLocate.ClearHighlights();
		}

		internal static void Debug(string message)
		{
			if (DebugEnabled)
			{
				ModLogger.LogInfo((object)("[DEBUG] " + message));
			}
		}

		internal static void DebugContainer(string message)
		{
			if (ContainerDebugEnabled)
			{
				ModLogger.LogInfo((object)("[DEBUG-CONTAINER] " + message));
			}
		}

		private unsafe void Update()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			WatchConfigFileForChanges();
			ItemLocate.Tick();
			if (ReloadConfigHotkey != null)
			{
				KeyboardShortcut value = ReloadConfigHotkey.Value;
				object obj = KeyboardShortcut.Empty;
				if (!((object)(*(KeyboardShortcut*)(&value))/*cast due to .constrained prefix*/).Equals(obj) && ((KeyboardShortcut)(ref value)).IsDown())
				{
					ReloadConfigFromDisk(notifyPlayer: true);
				}
			}
			if (Enabled == null || !Enabled.Value || EnableMassDeposit == null || !EnableMassDeposit.Value || MassDepositHotkey == null)
			{
				return;
			}
			KeyboardShortcut value2 = MassDepositHotkey.Value;
			if (((KeyboardShortcut)(ref value2)).IsDown())
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)localPlayer == (Object)null))
				{
					MassQuickDeposit(localPlayer);
				}
			}
		}

		private void WatchConfigFileForChanges()
		{
			if (AutoReloadConfig == null || !AutoReloadConfig.Value)
			{
				_configPendingSince = -1f;
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime < _configWatchNextCheck)
			{
				return;
			}
			_configWatchNextCheck = unscaledTime + 1f;
			DateTime configWriteTimeUtc = GetConfigWriteTimeUtc();
			if (!(configWriteTimeUtc == DateTime.MinValue))
			{
				if (configWriteTimeUtc == _configLastWriteUtc)
				{
					_configPendingSince = -1f;
				}
				else if (_configPendingSince < 0f || configWriteTimeUtc != _configPendingWriteUtc)
				{
					_configPendingWriteUtc = configWriteTimeUtc;
					_configPendingSince = unscaledTime;
				}
				else if (!(unscaledTime - _configPendingSince < 0.75f))
				{
					_configLastWriteUtc = configWriteTimeUtc;
					_configPendingSince = -1f;
					ReloadConfigFromDisk(notifyPlayer: false);
				}
			}
		}

		private DateTime GetConfigWriteTimeUtc()
		{
			try
			{
				string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
				if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath))
				{
					return DateTime.MinValue;
				}
				return File.GetLastWriteTimeUtc(configFilePath);
			}
			catch
			{
				return DateTime.MinValue;
			}
		}

		private void ReloadConfigFromDisk(bool notifyPlayer)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
				_configLastWriteUtc = GetConfigWriteTimeUtc();
				_configPendingSince = -1f;
				ResetRuntimeState();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Nearby Crafting Forked config reloaded from disk.");
				if (notifyPlayer)
				{
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)localPlayer == (Object)null))
					{
						((Character)localPlayer).Message((MessageType)2, "Nearby Crafting: config reloaded", 0, (Sprite)null, false);
					}
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Nearby Crafting Forked failed to reload config from disk.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
			}
		}

		private static void MassQuickDeposit(Player player)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<Container> list = NearbyContainers.Get(player);
			if (list.Count == 0)
			{
				if (DebugEnabled)
				{
					Debug("Mass quick-deposit: no eligible nearby containers.");
				}
				return;
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			List<Container> list2 = new List<Container>();
			for (int i = 0; i < list.Count; i++)
			{
				Container val = list[i];
				if ((Object)val == (Object)null)
				{
					continue;
				}
				try
				{
					Inventory inventory2 = val.GetInventory();
					if (inventory2 != null && inventory2 != inventory)
					{
						int num4 = QuickDepositIntoContainer(inventory, inventory2);
						num++;
						num3 += num4;
						if (num4 > 0)
						{
							num2++;
							list2.Add(val);
						}
						if (ContainerDebugEnabled)
						{
							DebugContainer($"Mass quick-deposit processed '{((Object)val).name}': moved={num4}.");
						}
					}
				}
				catch (Exception ex)
				{
					if (DebugEnabled)
					{
						Debug("Mass quick-deposit skipped '" + ((Object)val).name + "' after " + ex.GetType().Name + ": " + ex.Message);
					}
				}
			}
			NearbyContainers.InvalidateCounts();
			if (DebugEnabled)
			{
				Debug($"Mass quick-deposit completed across {num} eligible container(s); receiving={num2}; moved={num3} total item(s).");
			}
			string text = ((num3 > 0) ? string.Format("Quick Deposit: {0} item{1} deposited into {2} chest{3}", num3, (num3 == 1) ? "" : "s", num2, (num2 == 1) ? "" : "s") : "Quick Deposit: nothing to deposit");
			((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			if (QuickDepositHighlightChests != null && QuickDepositHighlightChests.Value && list2.Count > 0)
			{
				ItemLocate.HighlightContainers(list2, QuickDepositHighlightColor?.Value, new Color(0.14f, 0.5f, 0.22f, 1f), (QuickDepositHighlightDurationSeconds != null) ? QuickDepositHighlightDurationSeconds.Value : 15f, (QuickDepositHighlightAlpha != null) ? QuickDepositHighlightAlpha.Value : 1f);
			}
		}

		private static int QuickDepositIntoContainer(Inventory sourceInventory, Inventory targetInventory)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			List<ItemData> list = new List<ItemData>(targetInventory.GetAllItems());
			List<ItemData> list2 = new List<ItemData>(sourceInventory.GetAllItems());
			for (int i = 0; i < list2.Count; i++)
			{
				ItemData val = list2[i];
				if (val == null || val.m_shared == null || val.m_stack <= 0 || val.m_shared.m_maxStackSize <= 1)
				{
					continue;
				}
				if (IsQuickDepositExcluded(val))
				{
					if (ContainerDebugEnabled)
					{
						DebugContainer($"Quick-deposit excluded '{val.m_shared.m_name}' ({val.m_shared.m_itemType}).");
					}
					continue;
				}
				List<ItemData> list3 = new List<ItemData>();
				for (int j = 0; j < list.Count; j++)
				{
					ItemData val2 = list[j];
					if (CanQuickStackTogether(val, val2))
					{
						list3.Add(val2);
					}
				}
				if (list3.Count == 0)
				{
					continue;
				}
				for (int k = 0; k < list3.Count; k++)
				{
					if (val.m_stack <= 0)
					{
						break;
					}
					ItemData val3 = list3[k];
					if (val3 == null || val3.m_shared == null)
					{
						continue;
					}
					int num2 = val3.m_shared.m_maxStackSize - val3.m_stack;
					if (num2 > 0)
					{
						int num3 = Math.Min(val.m_stack, num2);
						int stack = val.m_stack;
						targetInventory.MoveItemToThis(sourceInventory, val, num3, val3.m_gridPos.x, val3.m_gridPos.y);
						int num4 = Math.Max(0, stack - val.m_stack);
						num += num4;
						if (ContainerDebugEnabled && num4 > 0)
						{
							DebugContainer($"Quick-deposit merged {num4}x '{val.m_shared.m_name}' into existing stack at {val3.m_gridPos.x},{val3.m_gridPos.y}.");
						}
					}
				}
				while (val.m_stack > 0)
				{
					int num5 = -1;
					int num6 = -1;
					for (int l = 0; l < targetInventory.GetHeight(); l++)
					{
						if (num5 >= 0)
						{
							break;
						}
						for (int m = 0; m < targetInventory.GetWidth(); m++)
						{
							if (targetInventory.GetItemAt(m, l) == null)
							{
								num5 = m;
								num6 = l;
								break;
							}
						}
					}
					if (num5 < 0 || num6 < 0)
					{
						break;
					}
					int num7 = Math.Min(val.m_stack, val.m_shared.m_maxStackSize);
					int stack2 = val.m_stack;
					targetInventory.MoveItemToThis(sourceInventory, val, num7, num5, num6);
					int num8 = Math.Max(0, stack2 - val.m_stack);
					if (num8 <= 0)
					{
						break;
					}
					num += num8;
					if (ContainerDebugEnabled)
					{
						DebugContainer($"Quick-deposit moved {num8}x '{val.m_shared.m_name}' into empty slot {num5},{num6}.");
					}
				}
			}
			return num;
		}

		private unsafe static bool IsQuickDepositExcluded(ItemData item)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Invalid comparison between Unknown and I4
			//IL_005e: 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_00af: Invalid comparison between Unknown and I4
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Invalid comparison between Unknown and I4
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Invalid comparison between Unknown and I4
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			if (QuickDepositExcludedItems != null && ItemMatchesCsv(item, QuickDepositExcludedItems.Value))
			{
				return true;
			}
			if (QuickDepositAllowedItems != null && ItemMatchesCsv(item, QuickDepositAllowedItems.Value))
			{
				if (ContainerDebugEnabled)
				{
					DebugContainer($"Quick-deposit allowed by exception '{item.m_shared.m_name}' ({item.m_shared.m_itemType}).");
				}
				return false;
			}
			ItemType itemType = item.m_shared.m_itemType;
			if (QuickDepositExcludeConsumables != null && QuickDepositExcludeConsumables.Value && (int)itemType == 2)
			{
				return true;
			}
			if (QuickDepositExcludeAmmo != null && QuickDepositExcludeAmmo.Value && ((int)itemType == 9 || (int)itemType == 23))
			{
				return true;
			}
			if (QuickDepositExcludeUtility != null && QuickDepositExcludeUtility.Value && (int)itemType == 18)
			{
				return true;
			}
			if (QuickDepositExcludeEquipment != null && QuickDepositExcludeEquipment.Value && IsEquipmentItemType(itemType))
			{
				return true;
			}
			if (QuickDepositExcludedItemTypes != null && CsvContains(QuickDepositExcludedItemTypes.Value, ((object)(*(ItemType*)(&itemType))/*cast due to .constrained prefix*/).ToString()))
			{
				return true;
			}
			return false;
		}

		private static bool ItemMatchesCsv(ItemData item, string csv)
		{
			if (string.IsNullOrWhiteSpace(csv) || item?.m_shared == null)
			{
				return false;
			}
			string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && ItemMatchesFilterPattern(item, text))
				{
					return true;
				}
			}
			return false;
		}

		private static bool ItemMatchesFilterPattern(ItemData item, string pattern)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			string name = item.m_shared.m_name;
			string localizedName = ItemLocate.GetLocalizedName(name);
			string text = null;
			if ((Object)item.m_dropPrefab != (Object)null)
			{
				text = ((Object)item.m_dropPrefab).name;
			}
			string leadingNameToken = GetLeadingNameToken(text);
			bool flag = pattern[0] == '*';
			if (!string.IsNullOrEmpty(localizedName) && !IsCompoundPrefabDump(localizedName, text) && NameMatches(localizedName, pattern))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(leadingNameToken) && NameMatches(leadingNameToken, pattern))
			{
				return true;
			}
			if (flag)
			{
				return false;
			}
			if (!string.IsNullOrEmpty(name) && NameMatches(name, pattern))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(name) && name[0] == '$' && NameMatches(name.Substring(1), pattern))
			{
				return true;
			}
			if (!string.IsNullOrEmpty(text) && NameMatches(text, pattern))
			{
				return true;
			}
			return false;
		}

		private static string GetLeadingNameToken(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return string.Empty;
			}
			int i;
			for (i = 1; i < name.Length; i++)
			{
				char c = name[i];
				if (c == '_' || c == '-' || c == ' ' || char.IsUpper(c))
				{
					break;
				}
			}
			return name.Substring(0, i);
		}

		private static bool IsCompoundPrefabDump(string candidate, string prefabName)
		{
			if (string.IsNullOrEmpty(candidate) || string.IsNullOrEmpty(prefabName))
			{
				return false;
			}
			if (GetLeadingNameToken(prefabName).Length >= prefabName.Length)
			{
				return false;
			}
			return string.Equals(candidate.Replace(" ", string.Empty), prefabName, StringComparison.OrdinalIgnoreCase);
		}

		private static bool IsEquipmentItemType(ItemType itemType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected I4, but got Unknown
			switch (itemType - 3)
			{
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 8:
			case 9:
			case 11:
			case 12:
			case 14:
			case 16:
			case 19:
			case 21:
				return true;
			default:
				return false;
			}
		}

		private static bool CsvContains(string csv, string value)
		{
			if (string.IsNullOrWhiteSpace(csv) || string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			string[] array = csv.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0 && NameMatches(value, text))
				{
					return true;
				}
			}
			return false;
		}

		internal static bool NameMatches(string value, string pattern)
		{
			if (string.IsNullOrEmpty(pattern))
			{
				return false;
			}
			if (pattern.IndexOf('*') < 0)
			{
				return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase);
			}
			string[] array = pattern.Split('*');
			int num = 0;
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				if (text.Length == 0)
				{
					continue;
				}
				if (i == 0)
				{
					if (!value.StartsWith(text, StringComparison.OrdinalIgnoreCase))
					{
						return false;
					}
					num = text.Length;
					continue;
				}
				if (i == array.Length - 1 && pattern[pattern.Length - 1] != '*')
				{
					if (!value.EndsWith(text, StringComparison.OrdinalIgnoreCase))
					{
						return false;
					}
					return value.Length - text.Length >= num;
				}
				int num2 = value.IndexOf(text, num, StringComparison.OrdinalIgnoreCase);
				if (num2 < 0)
				{
					return false;
				}
				num = num2 + text.Length;
			}
			return true;
		}

		private static bool CanQuickStackTogether(ItemData source, ItemData target)
		{
			if (source == null || target == null || source.m_shared == null || target.m_shared == null)
			{
				return false;
			}
			if (source.m_shared.m_name != target.m_shared.m_name || source.m_quality != target.m_quality || source.m_variant != target.m_variant || source.m_worldLevel != target.m_worldLevel)
			{
				return false;
			}
			if (source.m_customData.Count != target.m_customData.Count)
			{
				return false;
			}
			foreach (KeyValuePair<string, string> customDatum in source.m_customData)
			{
				if (!target.m_customData.TryGetValue(customDatum.Key, out var value) || value != customDatum.Value)
				{
					return false;
				}
			}
			return true;
		}

		private void OnDestroy()
		{
			Range.SettingChanged -= OnContainerSettingChanged;
			IgnoreMovingContainers.SettingChanged -= OnContainerSettingChanged;
			IgnoreObliterators.SettingChanged -= OnContainerSettingChanged;
			RequirePlayerPlacedContainer.SettingChanged -= OnContainerSettingChanged;
			BalrondCompatibility.SettingChanged -= OnContainerSettingChanged;
			Enabled.SettingChanged -= OnEnabledChanged;
			ResetRuntimeState();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class CraftingContext
	{
		internal static int Depth;

		internal static bool IsCrafting => Depth > 0;

		internal static void Clear()
		{
			Depth = 0;
		}
	}
	internal static class RecipeRequirementContext
	{
		internal static Player? Player;

		internal static Inventory? PlayerInventory;

		internal static int Depth;

		internal static bool IsActive
		{
			get
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Expected O, but got Unknown
				if (Depth > 0 && (Object)Player != (Object)null)
				{
					return PlayerInventory != null;
				}
				return false;
			}
		}

		internal static void Begin(Player player, bool discover)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (!discover && !((Object)player == (Object)null))
			{
				if (Depth == 0)
				{
					Player = player;
					PlayerInventory = ((Humanoid)player).GetInventory();
				}
				Depth++;
			}
		}

		internal static void End()
		{
			if (Depth > 0)
			{
				Depth--;
				if (Depth == 0)
				{
					Player = null;
					PlayerInventory = null;
				}
			}
		}

		internal static void Clear()
		{
			Depth = 0;
			Player = null;
			PlayerInventory = null;
		}
	}
	internal readonly struct RecipeConsumptionKey : IEquatable<RecipeConsumptionKey>
	{
		internal readonly Requirement[] Requirements;

		internal readonly int QualityLevel;

		internal RecipeConsumptionKey(Requirement[] requirements, int qualityLevel)
		{
			Requirements = requirements;
			QualityLevel = qualityLevel;
		}

		public bool Equals(RecipeConsumptionKey other)
		{
			if (Requirements == other.Requirements)
			{
				return QualityLevel == other.QualityLevel;
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is RecipeConsumptionKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (RuntimeHelpers.GetHashCode(Requirements) * 397) ^ QualityLevel;
		}
	}
	internal static class RecipeConsumptionRules
	{
		private static readonly Dictionary<RecipeConsumptionKey, HashSet<string>> AllowedNames = new Dictionary<RecipeConsumptionKey, HashSet<string>>();

		private static HashSet<string>? _currentNames;

		private static Requirement[]? _currentRequirements;

		private static int _currentQualityLevel;

		private static int _beginDepth;

		internal static void Begin(Recipe recipe, int qualityLevel)
		{
			if (_beginDepth > 0)
			{
				_beginDepth++;
				return;
			}
			_currentRequirements = recipe?.m_resources;
			_currentQualityLevel = qualityLevel;
			_currentNames = new HashSet<string>(StringComparer.Ordinal);
			_beginDepth = 1;
		}

		internal static void Record(string name)
		{
			if (_currentNames != null && !string.IsNullOrEmpty(name))
			{
				_currentNames.Add(name);
			}
		}

		internal static void Complete(bool success)
		{
			if (_beginDepth > 1)
			{
				_beginDepth--;
				return;
			}
			if (_beginDepth == 1 && success && _currentRequirements != null && _currentNames != null)
			{
				RecipeConsumptionKey key = new RecipeConsumptionKey(_currentRequirements, _currentQualityLevel);
				AllowedNames[key] = new HashSet<string>(_currentNames, StringComparer.Ordinal);
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Recorded {AllowedNames[key].Count} vanilla-consumed requirement name(s) " + $"for quality {_currentQualityLevel}.");
				}
			}
			_currentRequirements = null;
			_currentNames = null;
			_currentQualityLevel = 0;
			_beginDepth = 0;
		}

		internal static bool TryGet(Requirement[] requirements, int qualityLevel, out HashSet<string>? allowedNames)
		{
			if (requirements != null && AllowedNames.TryGetValue(new RecipeConsumptionKey(requirements, qualityLevel), out var value))
			{
				allowedNames = value;
				return true;
			}
			allowedNames = null;
			return false;
		}

		internal static void Clear()
		{
			AllowedNames.Clear();
			_currentRequirements = null;
			_currentNames = null;
			_currentQualityLevel = 0;
			_beginDepth = 0;
		}
	}
	internal static class BuildingPlacementState
	{
		private static Player? _lastPlacedPlayer;

		private static int _lastPlacedFrame = -1;

		internal static void MarkPlaced(Player player, bool placed)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			if (placed && !((Object)player == (Object)null))
			{
				_lastPlacedPlayer = player;
				_lastPlacedFrame = Time.frameCount;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Successful build placement marked for frame {_lastPlacedFrame}.");
				}
			}
		}

		internal static bool WasPlacedThisFrame(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected O, but got Unknown
			//IL_0023: Expected O, but got Unknown
			if ((Object)player != (Object)null && (Object)_lastPlacedPlayer == (Object)player)
			{
				return _lastPlacedFrame == Time.frameCount;
			}
			return false;
		}

		internal static void Clear()
		{
			_lastPlacedPlayer = null;
			_lastPlacedFrame = -1;
		}
	}
	internal readonly struct ItemCountKey : IEquatable<ItemCountKey>
	{
		internal readonly string Name;

		internal readonly int Quality;

		internal ItemCountKey(string name, int quality)
		{
			Name = name;
			Quality = quality;
		}

		public bool Equals(ItemCountKey other)
		{
			if (Quality == other.Quality)
			{
				return string.Equals(Name, other.Name, StringComparison.Ordinal);
			}
			return false;
		}

		public override bool Equals(object? obj)
		{
			if (obj is ItemCountKey other)
			{
				return Equals(other);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((Name != null) ? StringComparer.Ordinal.GetHashCode(Name) : 0) * 397) ^ Quality;
		}
	}
	internal readonly struct CachedCount
	{
		internal readonly int Value;

		internal readonly float CreatedAt;

		internal readonly int ContainerGeneration;

		internal CachedCount(int value, float createdAt, int containerGeneration)
		{
			Value = value;
			CreatedAt = createdAt;
			ContainerGeneration = containerGeneration;
		}
	}
	internal readonly struct ContainerTraits
	{
		internal readonly Container Container;

		internal readonly bool HasPiece;

		internal readonly bool IsMoving;

		internal readonly bool IsIncinerator;

		internal ContainerTraits(Container container, bool hasPiece, bool isMoving, bool isIncinerator)
		{
			Container = container;
			HasPiece = hasPiece;
			IsMoving = isMoving;
			IsIncinerator = isIncinerator;
		}
	}
	internal readonly struct ContainerDistance
	{
		internal readonly Container Container;

		internal readonly float DistanceSq;

		internal ContainerDistance(Container container, float distanceSq)
		{
			Container = container;
			DistanceSq = distanceSq;
		}
	}
	internal static class NearbyContainers
	{
		private const float ContainerCacheLifetime = 0.5f;

		private const float CountCacheLifetime = 0.1f;

		private const float MovementRefreshDistanceSq = 1f;

		private static readonly List<Container> CachedContainers = new List<Container>();

		private static readonly List<ContainerDistance> ScanBuffer = new List<ContainerDistance>();

		private static readonly Dictionary<ItemCountKey, CachedCount> CountCache = new Dictionary<ItemCountKey, CachedCount>();

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

		private static Player? _cachedPlayer;

		private static Vector3 _cachedPlayerPosition;

		private static float _containerCacheCreatedAt = -1000f;

		private static float _cachedRange = -1f;

		private static bool _cachedRequirePiece;

		private static bool _cachedIgnoreMoving;

		private static bool _cachedIgnoreObliterators;

		private static bool _cachedBalrondCompatibility;

		private static int _containerGeneration;

		internal static void InvalidateAll()
		{
			CachedContainers.Clear();
			ScanBuffer.Clear();
			CountCache.Clear();
			TraitCache.Clear();
			_cachedPlayer = null;
			_containerCacheCreatedAt = -1000f;
			_cachedRange = -1f;
			_containerGeneration++;
		}

		internal static void InvalidateCounts()
		{
			CountCache.Clear();
		}

		private static bool ContainerCacheIsValid(Player player, float now)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Expected O, but got Unknown
			//IL_0015: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)_cachedPlayer != (Object)player)
			{
				return false;
			}
			if (now - _containerCacheCreatedAt >= 0.5f)
			{
				return false;
			}
			Vector3 val = ((Component)player).transform.position - _cachedPlayerPosition;
			if (((Vector3)(ref val)).sqrMagnitude >= 1f)
			{
				return false;
			}
			if (!Mathf.Approximately(_cachedRange, NearbyCraftingForkedPlugin.Range.Value))
			{
				return false;
			}
			if (_cachedRequirePiece != NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value || _cachedIgnoreMoving != NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value || _cachedIgnoreObliterators != NearbyCraftingForkedPlugin.IgnoreObliterators.Value || _cachedBalrondCompatibility != NearbyCraftingForkedPlugin.BalrondCompatibility.Value)
			{
				return false;
			}
			return true;
		}

		internal static List<Container> Get(Player player)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if ((Object)player == (Object)null)
			{
				return CachedContainers;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (ContainerCacheIsValid(player, realtimeSinceStartup))
			{
				return CachedContainers;
			}
			RefreshContainerCache(player, realtimeSinceStartup);
			return CachedContainers;
		}

		private static void RefreshContainerCache(Player player, float now)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			CachedContainers.Clear();
			ScanBuffer.Clear();
			CountCache.Clear();
			PruneTraitCache();
			float num = Mathf.Max(0f, NearbyCraftingForkedPlugin.Range.Value);
			float num2 = num * num;
			Vector3 position = ((Component)player).transform.position;
			float num3 = (NearbyCraftingForkedPlugin.DebugEnabled ? Time.realtimeSinceStartup : 0f);
			Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
			Container[] array2 = array;
			foreach (Container val in array2)
			{
				if ((Object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled)
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - position;
				float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
				if (sqrMagnitude > num2)
				{
					if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer($"Ignoring '{((Object)val).name}': outside {num:0.0}m range.");
					}
					continue;
				}
				ContainerTraits traits = GetTraits(val);
				if (NearbyCraftingForkedPlugin.IgnoreObliterators.Value && traits.IsIncinerator)
				{
					if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': Obliterator/Incinerator.");
					}
					continue;
				}
				if (NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value && !traits.HasPiece)
				{
					if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': not attached to a player-placeable Piece.");
					}
					continue;
				}
				if (ShouldIgnoreMovingContainer(val, traits))
				{
					if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer("Ignoring '" + ((Object)val).name + "': moving container in active use (or ship).");
					}
					continue;
				}
				try
				{
					if (val.GetInventory() == null)
					{
						continue;
					}
				}
				catch (Exception ex)
				{
					if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer("Skipping '" + ((Object)val).name + "': GetInventory threw " + ex.GetType().Name + ": " + ex.Message);
					}
					continue;
				}
				ScanBuffer.Add(new ContainerDistance(val, sqrMagnitude));
				if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
				{
					NearbyCraftingForkedPlugin.DebugContainer($"Eligible '{((Object)val).name}' at {Mathf.Sqrt(sqrMagnitude):0.0}m.");
				}
			}
			ScanBuffer.Sort((ContainerDistance a, ContainerDistance b) => a.DistanceSq.CompareTo(b.DistanceSq));
			for (int num4 = 0; num4 < ScanBuffer.Count; num4++)
			{
				CachedContainers.Add(ScanBuffer[num4].Container);
			}
			_cachedPlayer = player;
			_cachedPlayerPosition = position;
			_containerCacheCreatedAt = now;
			_cachedRange = NearbyCraftingForkedPlugin.Range.Value;
			_cachedRequirePiece = NearbyCraftingForkedPlugin.RequirePlayerPlacedContainer.Value;
			_cachedIgnoreMoving = NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value;
			_cachedIgnoreObliterators = NearbyCraftingForkedPlugin.IgnoreObliterators.Value;
			_cachedBalrondCompatibility = NearbyCraftingForkedPlugin.BalrondCompatibility.Value;
			_containerGeneration++;
			if (NearbyCraftingForkedPlugin.DebugEnabled)
			{
				float num5 = (Time.realtimeSinceStartup - num3) * 1000f;
				NearbyCraftingForkedPlugin.Debug($"Container cache refreshed: scanned={array.Length}, eligible={CachedContainers.Count}, " + $"time={num5:0.00}ms.");
			}
		}

		private static void PruneTraitCache()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			if (TraitCache.Count == 0)
			{
				return;
			}
			List<int> list = null;
			foreach (KeyValuePair<int, ContainerTraits> item in TraitCache)
			{
				if ((Object)item.Value.Container == (Object)null)
				{
					if (list == null)
					{
						list = new List<int>();
					}
					list.Add(item.Key);
				}
			}
			if (list != null)
			{
				for (int i = 0; i < list.Count; i++)
				{
					TraitCache.Remove(list[i]);
				}
			}
		}

		private static bool ShouldIgnoreMovingContainer(Container container, ContainerTraits traits)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			if (!traits.IsMoving || NearbyCraftingForkedPlugin.IgnoreMovingContainers == null || !NearbyCraftingForkedPlugin.IgnoreMovingContainers.Value)
			{
				return false;
			}
			try
			{
				Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true);
				if ((Object)componentInParent != (Object)null)
				{
					if (componentInParent.InUse() || componentInParent.IsAttached())
					{
						return true;
					}
					return false;
				}
			}
			catch
			{
			}
			return true;
		}

		private static bool HasPlayerPlacedPiece(Container container)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			try
			{
				if ((Object)((Component)container).GetComponentInParent<Piece>() != (Object)null)
				{
					return true;
				}
				if (!NearbyCraftingForkedPlugin.BalrondCompatibility.Value)
				{
					return false;
				}
				Transform root = ((Component)container).transform.root;
				if ((Object)root == (Object)null)
				{
					return false;
				}
				Piece[] componentsInChildren = ((Component)root).GetComponentsInChildren<Piece>(true);
				bool flag = componentsInChildren != null && componentsInChildren.Length != 0;
				if (flag && NearbyCraftingForkedPlugin.ContainerDebugEnabled)
				{
					NearbyCraftingForkedPlugin.DebugContainer("Accepted '" + ((Object)container).name + "' through sibling-Piece compatibility fallback (root='" + ((Object)root).name + "').");
				}
				return flag;
			}
			catch (Exception ex)
			{
				if (NearbyCraftingForkedPlugin.ContainerDebugEnabled)
				{
					NearbyCraftingForkedPlugin.DebugContainer("Piece-layout inspection failed for '" + ((Object)container).name + "': " + ex.GetType().Name + ": " + ex.Message);
				}
				return false;
			}
		}

		private static ContainerTraits GetTraits(Container container)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			int instanceID = ((Object)container).GetInstanceID();
			if (TraitCache.TryGetValue(instanceID, out var value) && (Object)(object)value.Container == (Object)(object)container && (value.HasPiece || !NearbyCraftingForkedPlugin.BalrondCompatibility.Value))
			{
				return value;
			}
			bool hasPiece = HasPlayerPlacedPiece(container);
			bool flag = false;
			bool flag2 = false;
			try
			{
				if ((Object)((Component)container).GetComponentInParent<Incinerator>(true) != (Object)null)
				{
					flag2 = true;
				}
			}
			catch
			{
			}
			try
			{
				Component[] componentsInParent = ((Component)container).GetComponentsInParent<Component>(true);
				for (int i = 0; i < componentsInParent.Length; i++)
				{
					switch (((object)componentsInParent[i]).GetType().Name)
					{
					case "Ship":
					case "Vagon":
					case "Wagon":
						flag = true;
						break;
					case "Incinerator":
						flag2 = true;
						break;
					}
					if (flag && flag2)
					{
						break;
					}
				}
			}
			catch
			{
			}
			ContainerTraits containerTraits = new ContainerTraits(container, hasPiece, flag, flag2);
			TraitCache[instanceID] = containerTraits;
			return containerTraits;
		}

		internal static int CountCached(Player player, string sharedName, int quality = -1)
		{
			List<Container> containers = Get(player);
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			ItemCountKey key = new ItemCountKey(sharedName, quality);
			if (CountCache.TryGetValue(key, out var value) && value.ContainerGeneration == _containerGeneration && realtimeSinceStartup - value.CreatedAt < 0.1f)
			{
				return value.Value;
			}
			int num = CountAcross(player, containers, sharedName, quality);
			CountCache[key] = new CachedCount(num, realtimeSinceStartup, _containerGeneration);
			return num;
		}

		internal static int CountFresh(Player player, string sharedName, int quality = -1)
		{
			return CountAcross(player, Get(player), sharedName, quality);
		}

		private static int CountAcross(Player player, List<Container> containers, string sharedName, int quality)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = ((quality >= 0) ? inventory.CountItems(sharedName, quality, true) : inventory.CountItems(sharedName, -1, true));
			int num2 = num;
			for (int i = 0; i < containers.Count; i++)
			{
				Container val = containers[i];
				if ((Object)val == (Object)null)
				{
					continue;
				}
				Inventory inventory2;
				try
				{
					inventory2 = val.GetInventory();
				}
				catch
				{
					continue;
				}
				if (inventory2 != null)
				{
					int num3 = ((quality >= 0) ? inventory2.CountItems(sharedName, quality, true) : inventory2.CountItems(sharedName, -1, true));
					num2 += num3;
					if (num3 > 0 && NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer($"Count '{sharedName}': '{((Object)val).name}' contributes {num3}.");
					}
				}
			}
			if (NearbyCraftingForkedPlugin.DebugEnabled)
			{
				NearbyCraftingForkedPlugin.Debug($"Count '{sharedName}' (quality={quality}): player={num}, " + $"nearby={num2 - num}, total={num2}.");
			}
			return num2;
		}

		internal static int CountNearbyOnly(Player player, string sharedName, int quality, bool matchWorldLevel)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			if ((Object)player == (Object)null || string.IsNullOrEmpty(sharedName))
			{
				return 0;
			}
			List<Container> list = Get(player);
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				Container val = list[i];
				if ((Object)val == (Object)null)
				{
					continue;
				}
				Inventory inventory;
				try
				{
					inventory = val.GetInventory();
				}
				catch
				{
					continue;
				}
				if (inventory != null)
				{
					int num2 = inventory.CountItems(sharedName, quality, matchWorldLevel);
					num += num2;
					if (num2 > 0 && NearbyCraftingForkedPlugin.ContainerDebugEnabled)
					{
						NearbyCraftingForkedPlugin.DebugContainer($"Vanilla requirement count '{sharedName}': '{((Object)val).name}' contributes {num2}.");
					}
				}
			}
			return num;
		}

		private static Dictionary<string, int> AggregateRequirements(Requirement[] requirements, int qualityLevel, int multiplier, HashSet<string>? allowedNames = null)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			foreach (Requirement val in requirements)
			{
				if ((Object)(val?.m_resItem) == (Object)null)
				{
					continue;
				}
				int num = val.GetAmount(qualityLevel) * multiplier;
				if (num <= 0)
				{
					continue;
				}
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				int value;
				if (allowedNames != null && !allowedNames.Contains(name))
				{
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug("Skipping conditional requirement '" + name + "' during nearby consumption.");
					}
				}
				else if (dictionary.TryGetValue(name, out value))
				{
					dictionary[name] = value + num;
				}
				else
				{
					dictionary.Add(name, num);
				}
			}
			return dictionary;
		}

		internal static bool CanPayPlayerOnly(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null)
		{
			Dictionary<string, int> dictionary = AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames);
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				if (((itemQuality >= 0) ? inventory.CountItems(item.Key, itemQuality, true) : inventory.CountItems(item.Key, -1, true)) < item.Value)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool CanPayCombined(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null)
		{
			foreach (KeyValuePair<string, int> item in AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames))
			{
				int num = CountFresh(player, item.Key, itemQuality);
				if (num < item.Value)
				{
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug($"CanPayCombined=false for '{item.Key}': need={item.Value}, available={num}, " + $"qualityLevel={qualityLevel}, itemQuality={itemQuality}, multiplier={multiplier}.");
					}
					return false;
				}
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Combined requirement OK for '{item.Key}': need={item.Value}, available={num}.");
				}
			}
			return true;
		}

		internal static void Pay(Player player, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier, HashSet<string>? allowedNames = null)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			Dictionary<string, int> dictionary = AggregateRequirements(requirements, qualityLevel, multiplier, allowedNames);
			List<Container> list = Get(player);
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				string key = item.Key;
				int num = item.Value;
				int val = ((itemQuality >= 0) ? inventory.CountItems(key, itemQuality, true) : inventory.CountItems(key, -1, true));
				int num2 = Math.Min(num, val);
				if (num2 > 0)
				{
					inventory.RemoveItem(key, num2, itemQuality, true);
					num -= num2;
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug($"Consumed {num2}x '{key}' from player inventory; remaining={num}.");
					}
				}
				for (int i = 0; i < list.Count && num > 0; i++)
				{
					Container val2 = list[i];
					if ((Object)val2 == (Object)null)
					{
						continue;
					}
					Inventory inventory2;
					try
					{
						inventory2 = val2.GetInventory();
					}
					catch
					{
						continue;
					}
					if (inventory2 == null)
					{
						continue;
					}
					int val3 = ((itemQuality >= 0) ? inventory2.CountItems(key, itemQuality, true) : inventory2.CountItems(key, -1, true));
					int num3 = Math.Min(num, val3);
					if (num3 > 0)
					{
						inventory2.RemoveItem(key, num3, itemQuality, true);
						num -= num3;
						if (NearbyCraftingForkedPlugin.DebugEnabled)
						{
							NearbyCraftingForkedPlugin.Debug($"Consumed {num3}x '{key}' from container '{((Object)val2).name}'; remaining={num}.");
						}
					}
				}
				if (num > 0)
				{
					NearbyCraftingForkedPlugin.ModLogger.LogWarning((object)($"Resource consumption ended with {num}x '{key}' unpaid. " + "Container contents may have changed during crafting."));
				}
			}
			InvalidateCounts();
		}

		internal static bool HaveBuildRequirementsCombined(Player player, Piece piece)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if ((Object)piece == (Object)null || piece.m_resources == null)
			{
				return false;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			for (int i = 0; i < piece.m_resources.Length; i++)
			{
				Requirement val = piece.m_resources[i];
				if (!((Object)(val?.m_resItem) == (Object)null) && val.m_amount > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					if (dictionary.TryGetValue(name, out var value))
					{
						dictionary[name] = value + val.m_amount;
					}
					else
					{
						dictionary.Add(name, val.m_amount);
					}
				}
			}
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				int num = CountCached(player, item.Key);
				if (num < item.Value)
				{
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug("Build requirement failed for '" + ((Object)piece).name + "': '" + item.Key + "' " + $"needs={item.Value}, available={num}.");
					}
					return false;
				}
			}
			return true;
		}
	}
	internal readonly struct RequirementGraphicEntry
	{
		internal readonly Transform Root;

		internal readonly Graphic Graphic;

		internal RequirementGraphicEntry(Transform root, Graphic graphic)
		{
			Root = root;
			Graphic = graphic;
		}
	}
	internal static class RequirementUiCache
	{
		private static readonly Dictionary<int, RequirementGraphicEntry> Graphics = new Dictionary<int, RequirementGraphicEntry>();

		internal static Graphic? GetAmountGraphic(Transform elementRoot)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			int instanceID = ((Object)elementRoot).GetInstanceID();
			if (Graphics.TryGetValue(instanceID, out var value) && (Object)(object)value.Root == (Object)(object)elementRoot && (Object)value.Graphic != (Object)null)
			{
				return value.Graphic;
			}
			Transform val = elementRoot.Find("res_amount");
			if ((Object)val == (Object)null)
			{
				return null;
			}
			Graphic component = ((Component)val).GetComponent<Graphic>();
			if ((Object)component != (Object)null)
			{
				Graphics[instanceID] = new RequirementGraphicEntry(elementRoot, component);
			}
			return component;
		}

		internal static void Clear()
		{
			Graphics.Clear();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class DoCraftingContextPatch
	{
		private static void Prefix(ref bool __state)
		{
			__state = false;
			if (NearbyCraftingForkedPlugin.Enabled.Value)
			{
				CraftingContext.Depth++;
				__state = true;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"DoCrafting entered. CraftingContext.Depth={CraftingContext.Depth}.");
				}
			}
		}

		private static void Finalizer(bool __state, Exception? __exception)
		{
			if (__exception != null)
			{
				NearbyCraftingForkedPlugin.ModLogger.LogError((object)("DoCrafting threw " + __exception.GetType().Name + ": " + __exception.Message));
			}
			if (__state && CraftingContext.Depth > 0)
			{
				CraftingContext.Depth--;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"DoCrafting exited. CraftingContext.Depth={CraftingContext.Depth}.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[]
	{
		typeof(Recipe),
		typeof(bool),
		typeof(int),
		typeof(int)
	})]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class HaveRequirementItemsPatch
	{
		[HarmonyPriority(800)]
		private static void Prefix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			if (!(!NearbyCraftingForkedPlugin.Enabled.Value || discover) && !((Object)__instance == (Object)null) && !((Object)piece == (Object)null))
			{
				RecipeRequirementContext.Begin(__instance, discover);
				RecipeConsumptionRules.Begin(piece, qualityLevel);
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug("Vanilla recipe check with nearby counts enabled for '" + ((Object)piece).name + "' " + $"(qualityLevel={qualityLevel}, amount={amount}).");
				}
			}
		}

		[HarmonyPriority(0)]
		private static void Postfix(Recipe piece, bool discover, ref bool __result)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!(!NearbyCraftingForkedPlugin.Enabled.Value || discover) && !((Object)piece == (Object)null))
			{
				RecipeConsumptionRules.Complete(__result);
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Vanilla recipe check result for '{((Object)piece).name}' with nearby counts: {__result}.");
				}
			}
		}

		private static Exception? Finalizer(Exception? __exception)
		{
			if (__exception != null)
			{
				RecipeConsumptionRules.Complete(success: false);
			}
			RecipeRequirementContext.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Inventory), "CountItems", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(bool)
	})]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class InventoryCountItemsRequirementPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			if (!NearbyCraftingForkedPlugin.Enabled.Value || !RecipeRequirementContext.IsActive || __instance == null || __instance != RecipeRequirementContext.PlayerInventory)
			{
				return;
			}
			Player player = RecipeRequirementContext.Player;
			if ((Object)player == (Object)null)
			{
				return;
			}
			RecipeConsumptionRules.Record(name);
			int num = NearbyContainers.CountNearbyOnly(player, name, quality, matchWorldLevel);
			if (num > 0)
			{
				int num2 = __result;
				__result += num;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Vanilla CountItems augmented for '{name}': player={num2}, " + $"nearby={num}, total={__result}, quality={quality}, " + $"matchWorldLevel={matchWorldLevel}.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class TryPlacePiecePatch
	{
		private static void Postfix(Player __instance, bool __result)
		{
			if (NearbyCraftingForkedPlugin.Enabled.Value && NearbyCraftingForkedPlugin.EnableBuilding.Value)
			{
				BuildingPlacementState.MarkPlaced(__instance, __result);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class HaveBuildRequirementsPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			if (!((!NearbyCraftingForkedPlugin.Enabled.Value || !NearbyCraftingForkedPlugin.EnableBuilding.Value) | __result) && !((Object)__instance == (Object)null) && !((Object)piece == (Object)null) && (int)mode == 0 && (!((Object)piece.m_craftingStation != (Object)null) || Object.op_Implicit((Object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position))) && NearbyContainers.HaveBuildRequirementsCombined(__instance, piece))
			{
				__result = true;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug("HaveRequirements overridden to TRUE for build piece '" + ((Object)piece).name + "'.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class ConsumeResourcesPatch
	{
		[HarmonyPriority(700)]
		private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality = -1, int multiplier = 1)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			bool flag = NearbyCraftingForkedPlugin.EnableBuilding.Value && BuildingPlacementState.WasPlacedThisFrame(__instance);
			bool flag2 = CraftingContext.IsCrafting || flag;
			if (!NearbyCraftingForkedPlugin.Enabled.Value || !flag2 || (Object)__instance == (Object)null || requirements == null)
			{
				return true;
			}
			HashSet<string> allowedNames = null;
			if (CraftingContext.IsCrafting)
			{
				if (RecipeConsumptionRules.TryGet(requirements, qualityLevel, out HashSet<string> allowedNames2) && allowedNames2 != null)
				{
					allowedNames = allowedNames2;
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug($"Using vanilla-recorded requirement set for consumption: {allowedNames2.Count} name(s).");
					}
				}
				else if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug("No vanilla-recorded requirement set found for this craft; using unfiltered fallback.");
				}
			}
			if (NearbyContainers.CanPayPlayerOnly(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames))
			{
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug("Player inventory can fully pay; using vanilla ConsumeResources (context=" + (flag ? "building" : "crafting") + ").");
				}
				return true;
			}
			if (NearbyCraftingForkedPlugin.DebugEnabled)
			{
				NearbyCraftingForkedPlugin.Debug("ConsumeResources needs nearby storage for " + string.Format("{0}: requirements={1}, ", flag ? "building" : "crafting", requirements.Length) + $"qualityLevel={qualityLevel}, itemQuality={itemQuality}, multiplier={multiplier}.");
			}
			if (!NearbyContainers.CanPayCombined(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames))
			{
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug("Combined pre-flight failed; falling back to vanilla without partial chest consumption.");
				}
				return true;
			}
			NearbyContainers.Pay(__instance, requirements, qualityLevel, itemQuality, multiplier, allowedNames);
			if (NearbyCraftingForkedPlugin.DebugEnabled)
			{
				NearbyCraftingForkedPlugin.Debug("Nearby Crafting completed resource consumption; skipping vanilla ConsumeResources.");
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	[HarmonyAfter(new string[] { "balrond.astafaraios.BalrondConstructions" })]
	internal static class SetupRequirementDisplayPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (!NearbyCraftingForkedPlugin.Enabled.Value || !NearbyCraftingForkedPlugin.FixRequirementIndicator.Value || (Object)elementRoot == (Object)null || (Object)(req?.m_resItem) == (Object)null || (Object)player == (Object)null)
			{
				return;
			}
			Graphic amountGraphic = RequirementUiCache.GetAmountGraphic(elementRoot);
			if ((Object)amountGraphic == (Object)null)
			{
				return;
			}
			Color color = amountGraphic.color;
			if (color == Color.white)
			{
				return;
			}
			int amount = req.GetAmount(quality);
			if (amount <= 0)
			{
				return;
			}
			string name = req.m_resItem.m_itemData.m_shared.m_name;
			int num = NearbyContainers.CountCached(player, name);
			if (num >= amount)
			{
				amountGraphic.color = Color.white;
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"UI indicator corrected for '{name}': need={amount}, available={num}, " + $"previousColor={color}.");
				}
			}
		}
	}
	internal static class StationChestAssist
	{
		internal enum MoveToPlayerResult
		{
			Failed,
			InventoryFull,
			Moved
		}

		internal static readonly Func<Smelter, float>? SmelterGetFuel = CreateDelegate<Func<Smelter, float>>(typeof(Smelter), "GetFuel", Array.Empty<Type>());

		internal static readonly Func<CookingStation, float>? CookingGetFuel = CreateDelegate<Func<CookingStation, float>>(typeof(CookingStation), "GetFuel", Array.Empty<Type>());

		internal static readonly Func<ShieldGenerator, float>? ShieldGetFuel = CreateDelegate<Func<ShieldGenerator, float>>(typeof(ShieldGenerator), "GetFuel", Array.Empty<Type>());

		internal static readonly Func<Smelter, int>? SmelterGetQueueSize = CreateDelegate<Func<Smelter, int>>(typeof(Smelter), "GetQueueSize", Array.Empty<Type>());

		internal static readonly Func<Smelter, Inventory, ItemData>? SmelterFindCookableItem = CreateDelegate<Func<Smelter, Inventory, ItemData>>(typeof(Smelter), "FindCookableItem", new Type[1] { typeof(Inventory) });

		private static readonly FieldInfo? FireplaceNview = AccessTools.Field(typeof(Fireplace), "m_nview");

		internal static bool IsAssistEnabled
		{
			get
			{
				if (NearbyCraftingForkedPlugin.Enabled != null && NearbyCraftingForkedPlugin.Enabled.Value && NearbyCraftingForkedPlugin.StationFuelEnabled != null)
				{
					return NearbyCraftingForkedPlugin.StationFuelEnabled.Value;
				}
				return false;
			}
		}

		internal static void NotifyInventoryFull(Humanoid user)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if (!((Object)user == (Object)null))
			{
				((Character)user).Message((MessageType)2, "$msg_noroom", 0, (Sprite)null, false);
			}
		}

		internal static MoveToPlayerResult TryMoveOneToPlayer(Inventory from, Inventory to, ItemData item)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			if (from == null || to == null || item == null || (Object)item.m_dropPrefab == (Object)null)
			{
				return MoveToPlayerResult.Failed;
			}
			GameObject dropPrefab = item.m_dropPrefab;
			if (!to.CanAddItem(dropPrefab, 1))
			{
				return MoveToPlayerResult.InventoryFull;
			}
			if (!from.RemoveOneItem(item))
			{
				return MoveToPlayerResult.Failed;
			}
			if (!to.AddItem(dropPrefab, 1))
			{
				from.AddItem(dropPrefab, 1);
				return MoveToPlayerResult.InventoryFull;
			}
			return MoveToPlayerResult.Moved;
		}

		internal static bool TryPullOneToPlayer(Humanoid user, string sharedName)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_005c: 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_0070: Expected O, but got Unknown
			//IL_0070: Expected O, but got Unknown
			if (!IsAssistEnabled || (Object)(object)user == (Object)null || string.IsNullOrEmpty(sharedName))
			{
				return false;
			}
			Inventory inventory = user.GetInventory();
			if (inventory == null)
			{
				return false;
			}
			if (inventory.HaveItem(sharedName, true))
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)val == (Object)null)
			{
				val = Player.m_localPlayer;
			}
			if ((Object)val == (Object)null || (Object)val != (Object)Player.m_localPlayer)
			{
				return false;
			}
			List<Container> list = NearbyContainers.Get(val);
			for (int i = 0; i < list.Count; i++)
			{
				Container val2 = list[i];
				if ((Object)val2 == (Object)null)
				{
					continue;
				}
				Inventory inventory2;
				try
				{
					inventory2 = val2.GetInventory();
				}
				catch
				{
					continue;
				}
				if (inventory2 == null)
				{
					continue;
				}
				ItemData item = inventory2.GetItem(sharedName, -1, false);
				if (item == null)
				{
					continue;
				}
				switch (TryMoveOneToPlayer(inventory2, inventory, item))
				{
				case MoveToPlayerResult.InventoryFull:
					NotifyInventoryFull(user);
					return false;
				case MoveToPlayerResult.Moved:
					NearbyContainers.InvalidateCounts();
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug("Station fuel assist pulled 1x '" + sharedName + "' from '" + ((Object)val2).name + "'.");
					}
					return true;
				}
			}
			return false;
		}

		private static TDelegate? CreateDelegate<TDelegate>(Type type, string name, params Type[] parameters) where TDelegate : Delegate
		{
			MethodInfo methodInfo = ((parameters == null || parameters.Length == 0) ? AccessTools.Method(type, name, (Type[])null, (Type[])null) : AccessTools.Method(type, name, parameters, (Type[])null));
			if (methodInfo == null)
			{
				return null;
			}
			return AccessTools.MethodDelegate<TDelegate>(methodInfo, (object)null, true);
		}

		internal static bool TryPullFuelItemDrop(Humanoid user, ItemDrop? fuelItem)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if ((Object)fuelItem == (Object)null || fuelItem.m_itemData?.m_shared == null)
			{
				return false;
			}
			return TryPullOneToPlayer(user, fuelItem.m_itemData.m_shared.m_name);
		}

		internal static float GetFireplaceFuel(Fireplace fireplace)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			object? obj = FireplaceNview?.GetValue(fireplace);
			ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null);
			if ((Object)val == (Object)null || !val.IsValid())
			{
				return 0f;
			}
			return val.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	internal static class SmelterOnAddFuelPatch
	{
		private static void Prefix(Smelter __instance, Humanoid user, ItemData item)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (StationChestAssist.IsAssistEnabled && item == null && !((Object)__instance == (Object)null) && !((Object)user == (Object)null))
			{
				Func<Smelter, float> smelterGetFuel = StationChestAssist.SmelterGetFuel;
				if (smelterGetFuel == null || !(smelterGetFuel(__instance) > (float)(__instance.m_maxFuel - 1)))
				{
					StationChestAssist.TryPullFuelItemDrop(user, __instance.m_fuelItem);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	internal static class SmelterOnAddOrePatch
	{
		private static void Prefix(Smelter __instance, Humanoid user, ItemData item)
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Expected O, but got Unknown
			//IL_00b0: Expected O, but got Unknown
			Func<Smelter, Inventory, ItemData> smelterFindCookableItem = StationChestAssist.SmelterFindCookableItem;
			if (!StationChestAssist.IsAssistEnabled || NearbyCraftingForkedPlugin.EnableOreFromChests == null || !NearbyCraftingForkedPlugin.EnableOreFromChests.Value || item != null || (Object)__instance == (Object)null || (Object)user == (Object)null || smelterFindCookableItem == null)
			{
				return;
			}
			Func<Smelter, int> smelterGetQueueSize = StationChestAssist.SmelterGetQueueSize;
			if (smelterGetQueueSize != null && smelterGetQueueSize(__instance) >= __instance.m_maxOre)
			{
				return;
			}
			Inventory inventory = user.GetInventory();
			if (inventory == null || smelterFindCookableItem(__instance, inventory) != null)
			{
				return;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)val == (Object)null)
			{
				val = Player.m_localPlayer;
			}
			if ((Object)val == (Object)null || (Object)val != (Object)Player.m_localPlayer)
			{
				return;
			}
			List<Container> list = NearbyContainers.Get(val);
			for (int i = 0; i < list.Count; i++)
			{
				Container val2 = list[i];
				if ((Object)val2 == (Object)null)
				{
					continue;
				}
				Inventory inventory2;
				try
				{
					inventory2 = val2.GetInventory();
				}
				catch
				{
					continue;
				}
				if (inventory2 == null)
				{
					continue;
				}
				ItemData val3 = smelterFindCookableItem(__instance, inventory2);
				if (val3 == null)
				{
					continue;
				}
				switch (StationChestAssist.TryMoveOneToPlayer(inventory2, inventory, val3))
				{
				case StationChestAssist.MoveToPlayerResult.InventoryFull:
					StationChestAssist.NotifyInventoryFull(user);
					return;
				case StationChestAssist.MoveToPlayerResult.Moved:
					NearbyContainers.InvalidateCounts();
					if (NearbyCraftingForkedPlugin.DebugEnabled)
					{
						NearbyCraftingForkedPlugin.Debug("Station ore assist pulled '" + val3.m_shared?.m_name + "' from '" + ((Object)val2).name + "'.");
					}
					return;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Fireplace), "Interact")]
	internal static class FireplaceInteractPatch
	{
		private static void Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt)
		{
			bool willAddFuel = FireplaceFuelAssist.WillInteractAddFuel(__instance, hold, alt);
			FireplaceFuelAssist.TryAssist(__instance, user, willAddFuel);
		}
	}
	internal static class FireplaceFuelAssist
	{
		internal static bool WillInteractAddFuel(Fireplace fireplace, bool hold, bool alt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			if ((Object)fireplace == (Object)null || fireplace.m_infiniteFuel || !fireplace.m_canRefill)
			{
				return false;
			}
			float fireplaceFuel = StationChestAssist.GetFireplaceFuel(fireplace);
			if ((float)Mathf.CeilToInt(fireplaceFuel) >= fireplace.m_maxFuel)
			{
				return false;
			}
			if (fireplace.m_canTurnOff && !hold && !alt && fireplaceFuel > 0f)
			{
				return false;
			}
			return true;
		}

		internal static void TryAssist(Fireplace fireplace, Humanoid user, bool willAddFuel)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (willAddFuel && StationChestAssist.IsAssistEnabled && !((Object)fireplace == (Object)null) && !((Object)user == (Object)null))
			{
				StationChestAssist.TryPullFuelItemDrop(user, fireplace.m_fuelItem);
			}
		}
	}
	[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
	internal static class CookingStationOnAddFuelSwitchPatch
	{
		private static void Prefix(CookingStation __instance, Humanoid user, ItemData item)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if (StationChestAssist.IsAssistEnabled && item == null && !((Object)__instance == (Object)null) && !((Object)user == (Object)null) && __instance.m_useFuel)
			{
				Func<CookingStation, float> cookingGetFuel = StationChestAssist.CookingGetFuel;
				if (cookingGetFuel == null || !(cookingGetFuel(__instance) > (float)(__instance.m_maxFuel - 1)))
				{
					StationChestAssist.TryPullFuelItemDrop(user, __instance.m_fuelItem);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShieldGenerator), "OnAddFuel")]
	internal static class ShieldGeneratorOnAddFuelPatch
	{
		private static void Prefix(ShieldGenerator __instance, Humanoid user, ItemData item)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			if (!StationChestAssist.IsAssistEnabled || item != null || (Object)__instance == (Object)null || (Object)user == (Object)null)
			{
				return;
			}
			Func<ShieldGenerator, float> shieldGetFuel = StationChestAssist.ShieldGetFuel;
			if (shieldGetFuel != null && shieldGetFuel(__instance) >= (float)__instance.m_maxFuel)
			{
				return;
			}
			List<ItemDrop> fuelItems = __instance.m_fuelItems;
			if (fuelItems == null || fuelItems.Count == 0)
			{
				return;
			}
			Inventory inventory = user.GetInventory();
			if (inventory == null)
			{
				return;
			}
			for (int i = 0; i < fuelItems.Count; i++)
			{
				ItemDrop val = fuelItems[i];
				if (!((Object)val == (Object)null) && val.m_itemData?.m_shared != null)
				{
					string name = val.m_itemData.m_shared.m_name;
					if (inventory.HaveItem(name, true))
					{
						return;
					}
				}
			}
			for (int j = 0; j < fuelItems.Count && !StationChestAssist.TryPullFuelItemDrop(user, fuelItems[j]); j++)
			{
			}
		}
	}
	internal static class ItemLocate
	{
		private sealed class HighlightedChest
		{
			private readonly List<RendererGlow> _renderers = new List<RendererGlow>();

			internal static HighlightedChest? TryCreate(Container container)
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				Renderer[] highlightRenderers = GetHighlightRenderers(container);
				if (highlightRenderers == null || highlightRenderers.Length == 0)
				{
					return null;
				}
				HighlightedChest highlightedChest = new HighlightedChest();
				foreach (Renderer val in highlightRenderers)
				{
					if (!((Object)val == (Object)null) && !(val is ParticleSystemRenderer) && !(val is LineRenderer) && !(val is TrailRenderer))
					{
						RendererGlow rendererGlow = RendererGlow.TryCreate(val);
						if (rendererGlow != null)
						{
							highlightedChest._renderers.Add(rendererGlow);
						}
					}
				}
				if (highlightedChest._renderers.Count == 0)
				{
					return null;
				}
				return highlightedChest;
			}

			private static Renderer[] GetHighlightRenderers(Container container)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Expected O, but got Unknown
				Component val = (Component)(object)container;
				try
				{
					Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(true);
					if ((Object)componentInParent != (Object)null)
					{
						val = (Component)(object)componentInParent;
					}
				}
				catch
				{
				}
				return val.GetComponentsInChildren<Renderer>(true);
			}

			internal void ApplyGlow(Color color)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < _renderers.Count; i++)
				{
					_renderers[i].Apply(color);
				}
			}

			internal void Restore()
			{
				for (int i = 0; i < _renderers.Count; i++)
				{
					_renderers[i].Restore();
				}
				_renderers.Clear();
			}
		}

		private sealed class RendererGlow
		{
			private readonly Renderer _renderer;

			private readonly bool _usedMaterialInstances;

			private readonly Material[]? _originalSharedMaterials;

			private readonly Material[]? _instancedMaterials;

			private readonly Color[]? _originalEmission;

			private readonly bool[]? _hadEmissionKeyword;

			private RendererGlow(Renderer renderer, bool usedMaterialInstances, Material[]? originalSharedMaterials, Material[]? instancedMaterials, Color[]? originalEmission, bool[]? hadEmissionKeyword)
			{
				_renderer = renderer;
				_usedMaterialInstances = usedMaterialInstances;
				_originalSharedMaterials = originalSharedMaterials;
				_instancedMaterials = instancedMaterials;
				_originalEmission = originalEmission;
				_hadEmissionKeyword = hadEmissionKeyword;
			}

			internal static RendererGlow? TryCreate(Renderer renderer)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0097: Expected O, but got Unknown
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Expected O, but got Unknown
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_011e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0129: Expected O, but got Unknown
				//IL_012f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Expected O, but got Unknown
				//IL_0142: Expected O, but got Unknown
				Material[] sharedMaterials = renderer.sharedMaterials;
				if (sharedMaterials == null || sharedMaterials.Length == 0)
				{
					return null;
				}
				renderer.GetPropertyBlock(PropertyBlock);
				PropertyBlock.SetColor("_EmissionColor", Color.black);
				renderer.SetPropertyBlock(PropertyBlock);
				if (SupportsEmissionViaPropertyBlock(renderer))
				{
					return new RendererGlow(renderer, usedMaterialInstances: false, null, null, null, null);
				}
				Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
				Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length];
				Color[] array3 = (Color[])(object)new Color[sharedMaterials.Length];
				bool[] array4 = new bool[sharedMaterials.Length];
				bool flag = false;
				for (int i = 0; i < sharedMaterials.Length; i++)
				{
					Material val = (array[i] = sharedMaterials[i]);
					if ((Object)val == (Object)null)
					{
						array2[i] = val;
						continue;
					}
					Material val2 = (array2[i] = new Material(val));
					array4[i] = val2.IsKeywordEnabled("_EMISSION");
					if (val2.HasProperty("_EmissionColor"))
					{
						array3[i] = val2.GetColor("_EmissionColor");
						val2.EnableKeyword("_EMISSION");
						flag = true;
					}
					else
					{
						array3[i] = Color.black;
					}
				}
				if (!flag)
				{
					for (int j = 0; j < array2.Length; j++)
					{
						if ((Object)array2[j] != (Object)null && (Object)array2[j] != (Object)array[j])
						{
							Object.Destroy((Object)(object)array2[j]);
						}
					}
					return null;
				}
				renderer.materials = array2;
				return new RendererGlow(renderer, usedMaterialInstances: true, array, array2, array3, array4);
			}

			private static bool SupportsEmissionViaPropertyBlock(Renderer renderer)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_001b: Expected O, but got Unknown
				Material[] sharedMaterials = renderer.sharedMaterials;
				foreach (Material val in sharedMaterials)
				{
					if ((Object)val != (Object)null && val.HasProperty("_EmissionColor"))
					{
						return true;
					}
				}
				return false;
			}

			internal void Apply(Color color)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0064: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Expected O, but got Unknown
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)_renderer == (Object)null)
				{
					return;
				}
				if (!_usedMaterialInstances)
				{
					_renderer.GetPropertyBlock(PropertyBlock);
					PropertyBlock.SetColor("_EmissionColor", color);
					_renderer.SetPropertyBlock(PropertyBlock);
				}
				else
				{
					if (_instancedMaterials == null)
					{
						return;
					}
					for (int i = 0; i < _instancedMaterials.Length; i++)
					{
						Material val = _instancedMaterials[i];
						if ((Object)val != (Object)null && val.HasProperty("_EmissionColor"))
						{
							val.SetColor("_EmissionColor", color);
						}
					}
				}
			}

			internal void Restore()
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Expected O, but got Unknown
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Expected O, but got Unknown
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)_renderer == (Object)null)
				{
					return;
				}
				if (!_usedMaterialInstances)
				{
					_renderer.GetPropertyBlock(PropertyBlock);
					PropertyBlock.SetColor("_EmissionColor", Color.black);
					_renderer.SetPropertyBlock(PropertyBlock);
					return;
				}
				if (_originalSharedMaterials != null)
				{
					_renderer.sharedMaterials = _originalSharedMaterials;
				}
				if (_instancedMaterials == null)
				{
					return;
				}
				for (int i = 0; i < _instancedMaterials.Length; i++)
				{
					Material val = _instancedMaterials[i];
					if (!((Object)val == (Object)null))
					{
						if (_originalEmission != null && val.HasProperty("_EmissionColor"))
						{
							val.SetColor("_EmissionColor", _originalEmission[i]);
						}
						if (_hadEmissionKeyword != null && !_hadEmissionKeyword[i])
						{
							val.DisableKeyword("_EMISSION");
						}
						Object.Destroy((Object)(object)val);
					}
				}
			}
		}

		private const string EmissionColorProperty = "_EmissionColor";

		private static readonly List<HighlightedChest> Active = new List<HighlightedChest>();

		private static readonly MaterialPropertyBlock PropertyBlock = new MaterialPropertyBlock();

		private static bool _commandRegistered;

		private static float _activeUntil = -1f;

		private static Color _baseGlow = new Color(0.55f, 0.45f, 0.1f, 1f);

		private static float _glowAlpha = 1f;

		private static Func<string, string> _localizeName;

		private static bool _localizeResolved;

		internal static void RegisterCommand()
		{
			if (!_commandRegistered)
			{
				_commandRegistered = true;
				RegisterOne("nearby", "[item|clear] Highlight nearby eligible chests and carts containing an item (or clear). No args uses held item.");
				RegisterOne("locate", "[item|clear] Alias for nearby — highlight chests and carts containing an item.");
			}
		}

		private static void RegisterOne(string command, string description)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			new ConsoleCommand(command, description, new ConsoleEvent(OnCommand), false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		internal static void ClearHighlights()
		{
			for (int i = 0; i < Active.Count; i++)
			{
				Active[i].Restore();
			}
			Active.Clear();
			_activeUntil = -1f;
		}

		internal static void HighlightContainers(List<Container> containers, string? colorRaw, Color fallback, float durationSeconds, float alpha)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			ClearHighlights();
			if (containers == null || containers.Count == 0)
			{
				return;
			}
			_baseGlow = ParseGlowColor(colorRaw, fallback);
			_glowAlpha = Mathf.Clamp01(alpha);
			float num = Mathf.Clamp(durationSeconds, 1f, 120f);
			for (int i = 0; i < containers.Count; i++)
			{
				Container val = containers[i];
				if (!((Object)val == (Object)null))
				{
					HighlightedChest highlightedChest = HighlightedChest.TryCreate(val);
					if (highlightedChest != null)
					{
						Active.Add(highlightedChest);
					}
				}
			}
			if (Active.Count != 0)
			{
				_activeUntil = Time.realtimeSinceStartup + num;
				Tick();
				if (NearbyCraftingForkedPlugin.DebugEnabled)
				{
					NearbyCraftingForkedPlugin.Debug($"Quick-deposit highlight: glowing={Active.Count}, duration={num:0.#}s.");
				}
			}
		}

		internal static void Tick()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if (Active.Count == 0)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup >= _activeUntil)
			{
				ClearHighlights();
				return;
			}
			float num = (0.45f + 0.55f * (0.5f + 0.5f * Mathf.Sin(realtimeSinceStartup * 5f))) * _glowAlpha;
			Color color