Decompiled source of CraftingFromContainers v0.0.1

CraftFromContainers.dll

Decompiled 6 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CraftFromContainers;

[BepInPlugin("aedenthorn.CraftFromContainers", "Craft From Containers", "3.5.1")]
public class BepInExPlugin : BaseUnityPlugin
{
	public class ConnectionParams
	{
		public GameObject connection;

		public Vector3 stationPos;
	}

	[HarmonyPatch(typeof(FejdStartup), "Awake")]
	private static class FejdStartup_Awake_Patch
	{
		private static void Postfix(FejdStartup __instance)
		{
			if (modEnabled.Value)
			{
				CheckOdinsQOLConfig();
			}
		}
	}

	[HarmonyPatch(typeof(Container), "Awake")]
	private static class Container_Awake_Patch
	{
		private static void Postfix(Container __instance, ZNetView ___m_nview)
		{
			((MonoBehaviour)context).StartCoroutine(AddContainer(__instance, ___m_nview));
		}
	}

	[HarmonyPatch(typeof(Container), "OnDestroyed")]
	private static class Container_OnDestroyed_Patch
	{
		private static void Prefix(Container __instance)
		{
			containerList.Remove(__instance);
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "Update")]
	private static class InventoryGui_Update_Patch
	{
		private static void Prefix(InventoryGui __instance, Animator ___m_animator)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && wasAllowed != AllowByKey() && ___m_animator.GetBool("visible"))
			{
				AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { false });
			}
		}
	}

	[HarmonyPatch(typeof(Fireplace), "Interact")]
	private static class Fireplace_Interact_Patch
	{
		private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, ref bool __result, ZNetView ___m_nview)
		{
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			__result = true;
			bool flag = CheckKeyHeld(fillAllModKey.Value);
			Inventory inventory = user.GetInventory();
			if (!AllowByKey() || hold || inventory == null || (inventory.HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true) && !flag))
			{
				return true;
			}
			if (!___m_nview.HasOwner())
			{
				___m_nview.ClaimOwnership();
			}
			if (flag && inventory.HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true))
			{
				int num = (int)Mathf.Min(__instance.m_maxFuel - (float)Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)), (float)inventory.CountItems(__instance.m_fuelItem.m_itemData.m_shared.m_name, -1, true));
				inventory.RemoveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, num, -1, true);
				typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(inventory, new object[0]);
				for (int i = 0; i < num; i++)
				{
					___m_nview.InvokeRPC("RPC_AddFuel", new object[0]);
				}
				((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_fireadding", new string[1] { __instance.m_fuelItem.m_itemData.m_shared.m_name }), 0, (Sprite)null);
				__result = false;
			}
			if (!inventory.HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true) && (float)Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)) < __instance.m_maxFuel)
			{
				foreach (Container nearbyContainer in GetNearbyContainers(((Component)__instance).transform.position))
				{
					ItemData item = nearbyContainer.GetInventory().GetItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, -1, false);
					if (item == null || !((float)Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)) < __instance.m_maxFuel))
					{
						continue;
					}
					if (fuelDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item.m_dropPrefab).name))
					{
						Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item.m_stack} {((Object)item.m_dropPrefab).name} but it's forbidden by config");
						continue;
					}
					int num2 = ((!flag) ? 1 : ((int)Mathf.Min(__instance.m_maxFuel - (float)Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)), (float)item.m_stack)));
					Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item.m_stack} {((Object)item.m_dropPrefab).name}, taking {num2}");
					nearbyContainer.GetInventory().RemoveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, num2, -1, true);
					typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(nearbyContainer, new object[0]);
					if (__result)
					{
						((Character)user).Message((MessageType)2, Localization.instance.Localize("$msg_fireadding", new string[1] { __instance.m_fuelItem.m_itemData.m_shared.m_name }), 0, (Sprite)null);
					}
					for (int j = 0; j < num2; j++)
					{
						___m_nview.InvokeRPC("RPC_AddFuel", new object[0]);
					}
					__result = false;
					if (flag && !((float)Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)) >= __instance.m_maxFuel))
					{
						continue;
					}
					return false;
				}
			}
			return __result;
		}
	}

	[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
	private static class CookingStation_OnAddFuelSwitch_Patch
	{
		private static bool Prefix(CookingStation __instance, ref bool __result, Humanoid user, ItemData item, ZNetView ___m_nview)
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			Dbgl("looking for fuel");
			if (modEnabled.Value && AllowByKey() && item == null && (float)((object)__instance).GetType().GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0]) <= (float)(__instance.m_maxFuel - 1) && !user.GetInventory().HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true))
			{
				Dbgl("missing fuel in player inventory");
				foreach (Container nearbyContainer in GetNearbyContainers(((Component)__instance).transform.position))
				{
					ItemData item2 = nearbyContainer.GetInventory().GetItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, -1, false);
					if (item2 != null)
					{
						if (!fuelDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item2.m_dropPrefab).name))
						{
							Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item2.m_stack} {((Object)item2.m_dropPrefab).name}, taking one");
							nearbyContainer.GetInventory().RemoveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, 1, -1, true);
							typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(nearbyContainer, new object[0]);
							((Character)user).Message((MessageType)2, "$msg_added " + __instance.m_fuelItem.m_itemData.m_shared.m_name, 0, (Sprite)null);
							___m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
							__result = true;
							return false;
						}
						Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item2.m_stack} {((Object)item2.m_dropPrefab).name} but it's forbidden by config");
					}
				}
				return true;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(CookingStation), "FindCookableItem")]
	private static class CookingStation_FindCookableItem_Patch
	{
		private static void Postfix(CookingStation __instance, ref ItemData __result)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			Dbgl("looking for cookable");
			if (!modEnabled.Value || !AllowByKey() || __result != null || (__instance.m_requireFire && !(bool)typeof(CookingStation).GetMethod("IsFireLit", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0])) || (int)typeof(CookingStation).GetMethod("GetFreeSlot", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0]) == -1)
			{
				return;
			}
			Dbgl("missing cookable in player inventory");
			List<Container> nearbyContainers = GetNearbyContainers(((Component)__instance).transform.position);
			foreach (ItemConversion item2 in __instance.m_conversion)
			{
				foreach (Container item3 in nearbyContainers)
				{
					ItemData item = item3.GetInventory().GetItem(item2.m_from.m_itemData.m_shared.m_name, -1, false);
					if (item != null)
					{
						if (!oreDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item.m_dropPrefab).name))
						{
							Dbgl($"container at {((Component)item3).transform.position} has {item.m_stack} {((Object)item.m_dropPrefab).name}, taking one");
							__result = item;
							item3.GetInventory().RemoveItem(item2.m_from.m_itemData.m_shared.m_name, 1, -1, true);
							typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(item3, new object[0]);
							return;
						}
						Dbgl($"container at {((Component)item3).transform.position} has {item.m_stack} {((Object)item.m_dropPrefab).name} but it's forbidden by config");
					}
				}
			}
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")]
	private static class Smelter_OnHoverAddFuel_Patch
	{
		private static void Postfix(Smelter __instance, ref string __result)
		{
			if (modEnabled.Value)
			{
				string value = fillAllModKey.Value;
				if (value != null && value.Length > 0)
				{
					__result += Localization.instance.Localize("\n[<color=yellow><b>" + fillAllModKey.Value + "+$KEY_Use</b></color>] $piece_smelter_add max");
				}
			}
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnHoverAddOre")]
	private static class Smelter_OnHoverAddOre_Patch
	{
		private static void Postfix(Smelter __instance, ref string __result)
		{
			if (modEnabled.Value)
			{
				string value = fillAllModKey.Value;
				if (value != null && value.Length > 0)
				{
					__result += Localization.instance.Localize("\n[<color=yellow><b>" + fillAllModKey.Value + "+$KEY_Use</b></color>] " + __instance.m_addOreTooltip + " max");
				}
			}
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	private static class Smelter_OnAddOre_Patch
	{
		private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ZNetView ___m_nview)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_031d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			bool flag = CheckKeyHeld(fillAllModKey.Value);
			if (modEnabled.Value && (AllowByKey() || flag) && item == null && Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>() < __instance.m_maxOre)
			{
				Inventory inventory = user.GetInventory();
				foreach (ItemConversion item4 in __instance.m_conversion)
				{
					if (inventory.HaveItem(item4.m_from.m_itemData.m_shared.m_name, true) && !flag)
					{
						return true;
					}
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				List<Container> nearbyContainers = GetNearbyContainers(((Component)__instance).transform.position);
				foreach (ItemConversion item5 in __instance.m_conversion)
				{
					if (Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>() >= __instance.m_maxOre || (dictionary.Any() && !flag))
					{
						break;
					}
					string name = item5.m_from.m_itemData.m_shared.m_name;
					if (flag && inventory.HaveItem(name, true))
					{
						ItemData item2 = inventory.GetItem(name, -1, false);
						if (oreDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item2.m_dropPrefab).name))
						{
							Dbgl($"player has {item2.m_stack} {((Object)item2.m_dropPrefab).name} but it's forbidden by config");
							continue;
						}
						int num = ((!flag) ? 1 : Mathf.Min(__instance.m_maxOre - Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>(), inventory.CountItems(name, -1, true)));
						if (!dictionary.ContainsKey(name))
						{
							dictionary[name] = 0;
						}
						dictionary[name] += num;
						inventory.RemoveItem(item5.m_from.m_itemData.m_shared.m_name, num, -1, true);
						for (int i = 0; i < num; i++)
						{
							___m_nview.InvokeRPC("RPC_AddOre", new object[1] { ((Object)item2.m_dropPrefab).name });
						}
						((Character)user).Message((MessageType)1, $"$msg_added {num} {name}", 0, (Sprite)null);
						if (Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>() >= __instance.m_maxOre)
						{
							break;
						}
					}
					foreach (Container item6 in nearbyContainers)
					{
						ItemData item3 = item6.GetInventory().GetItem(name, -1, false);
						if (item3 == null)
						{
							continue;
						}
						if (oreDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item3.m_dropPrefab).name))
						{
							Dbgl($"container at {((Component)item6).transform.position} has {item3.m_stack} {((Object)item3.m_dropPrefab).name} but it's forbidden by config");
							continue;
						}
						int num2 = ((!flag) ? 1 : Mathf.Min(__instance.m_maxOre - Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>(), item6.GetInventory().CountItems(name, -1, true)));
						if (!dictionary.ContainsKey(name))
						{
							dictionary[name] = 0;
						}
						dictionary[name] += num2;
						Dbgl($"container at {((Component)item6).transform.position} has {item3.m_stack} {((Object)item3.m_dropPrefab).name}, taking {num2}");
						item6.GetInventory().RemoveItem(name, num2, -1, true);
						typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(item6, new object[0]);
						for (int j = 0; j < num2; j++)
						{
							___m_nview.InvokeRPC("RPC_AddOre", new object[1] { ((Object)item3.m_dropPrefab).name });
						}
						((Character)user).Message((MessageType)1, $"$msg_added {num2} {name}", 0, (Sprite)null);
						if (Traverse.Create((object)__instance).Method("GetQueueSize", Array.Empty<object>()).GetValue<int>() < __instance.m_maxOre && flag)
						{
							continue;
						}
						break;
					}
				}
				if (!dictionary.Any())
				{
					((Character)user).Message((MessageType)2, "$msg_noprocessableitems", 0, (Sprite)null);
				}
				else
				{
					List<string> list = new List<string>();
					foreach (KeyValuePair<string, int> item7 in dictionary)
					{
						list.Add($"$msg_added {item7.Value} {item7.Key}");
					}
					((Character)user).Message((MessageType)2, string.Join("\n", list), 0, (Sprite)null);
				}
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	private static class Smelter_OnAddFuel_Patch
	{
		private static bool Prefix(Smelter __instance, ref bool __result, ZNetView ___m_nview, Humanoid user, ItemData item)
		{
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
			bool flag = CheckKeyHeld(fillAllModKey.Value);
			Inventory inventory = user.GetInventory();
			if (!modEnabled.Value || (!AllowByKey() && !flag) || item != null || inventory == null || (inventory.HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true) && !flag))
			{
				return true;
			}
			__result = true;
			int num = 0;
			if ((float)typeof(Smelter).GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0]) <= (float)(__instance.m_maxFuel - 1))
			{
				if (flag && inventory.HaveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, true))
				{
					int num2 = (int)Mathf.Min((float)__instance.m_maxFuel - (float)typeof(Smelter).GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0]), (float)inventory.CountItems(__instance.m_fuelItem.m_itemData.m_shared.m_name, -1, true));
					inventory.RemoveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, num2, -1, true);
					for (int i = 0; i < num2; i++)
					{
						___m_nview.InvokeRPC("RPC_AddFuel", new object[0]);
					}
					num += num2;
					((Character)user).Message((MessageType)1, Localization.instance.Localize("$msg_fireadding", new string[1] { __instance.m_fuelItem.m_itemData.m_shared.m_name }), 0, (Sprite)null);
					__result = false;
				}
				foreach (Container nearbyContainer in GetNearbyContainers(((Component)__instance).transform.position))
				{
					ItemData item2 = nearbyContainer.GetInventory().GetItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, -1, false);
					if (item2 == null)
					{
						continue;
					}
					if (fuelDisallowTypes.Value.Split(new char[1] { ',' }).Contains(((Object)item2.m_dropPrefab).name))
					{
						Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item2.m_stack} {((Object)item2.m_dropPrefab).name} but it's forbidden by config");
						continue;
					}
					int num3 = ((!flag) ? 1 : ((int)Mathf.Min((float)__instance.m_maxFuel - (float)typeof(Smelter).GetMethod("GetFuel", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(__instance, new object[0]), (float)item2.m_stack)));
					Dbgl($"container at {((Component)nearbyContainer).transform.position} has {item2.m_stack} {((Object)item2.m_dropPrefab).name}, taking {num3}");
					nearbyContainer.GetInventory().RemoveItem(__instance.m_fuelItem.m_itemData.m_shared.m_name, num3, -1, true);
					typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(nearbyContainer, new object[0]);
					for (int j = 0; j < num3; j++)
					{
						___m_nview.InvokeRPC("RPC_AddFuel", new object[0]);
					}
					num += num3;
					((Character)user).Message((MessageType)1, "$msg_added " + __instance.m_fuelItem.m_itemData.m_shared.m_name, 0, (Sprite)null);
					__result = false;
					if (flag && Mathf.CeilToInt(___m_nview.GetZDO().GetFloat("fuel", 0f)) < __instance.m_maxFuel)
					{
						continue;
					}
					return false;
				}
				if (num == 0)
				{
					((Character)user).Message((MessageType)2, "$msg_noprocessableitems", 0, (Sprite)null);
				}
				else
				{
					((Character)user).Message((MessageType)2, $"$msg_added {num} {__instance.m_fuelItem.m_itemData.m_shared.m_name}", 0, (Sprite)null);
				}
				return __result;
			}
			((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null);
			__result = false;
			return false;
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	private static class InventoryGui_SetupRequirement_Patch
	{
		private static void Postfix(InventoryGui __instance, Transform elementRoot, Requirement req, Player player, bool craft, int quality)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled.Value || !AllowByKey() || !((Object)(object)req.m_resItem != (Object)null))
			{
				return;
			}
			int num = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true);
			int amount = req.GetAmount(quality);
			if (amount <= 0)
			{
				return;
			}
			TMP_Text component = ((Component)((Component)elementRoot).transform.Find("res_amount")).GetComponent<TMP_Text>();
			if (num < amount)
			{
				foreach (Container nearbyContainer in GetNearbyContainers(((Component)Player.m_localPlayer).transform.position))
				{
					num += nearbyContainer.GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true);
				}
				if (num >= amount)
				{
					((Graphic)component).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? flashColor.Value : unFlashColor.Value);
				}
			}
			if (resourceString.Value.Trim().Length > 0)
			{
				component.text = string.Format(resourceString.Value, num, amount);
			}
			else
			{
				component.text = amount.ToString();
			}
		}
	}

	private static class InventoryGui_UpdateRecipeList_Patch
	{
		private static void Postfix(InventoryGui __instance, List<GameObject> ___m_recipeList)
		{
			if (!modEnabled.Value || !AllowByKey() || ___m_recipeList.Count == 0)
			{
				return;
			}
			foreach (GameObject ___m_recipe in ___m_recipeList)
			{
				_ = ___m_recipe;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[]
	{
		typeof(Recipe),
		typeof(bool),
		typeof(int)
	})]
	private static class HaveRequirementItems_Patch
	{
		private static void Postfix(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, HashSet<string> ___m_knownMaterial)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((!modEnabled.Value | __result) || discover || !AllowByKey())
			{
				return;
			}
			List<Container> nearbyContainers = GetNearbyContainers(((Component)__instance).transform.position);
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!Object.op_Implicit((Object)(object)val.m_resItem))
				{
					continue;
				}
				int amount = val.GetAmount(qualityLevel);
				int num = ((Humanoid)__instance).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
				if (num >= amount)
				{
					continue;
				}
				foreach (Container item in nearbyContainers)
				{
					num += item.GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
				}
				if (num < amount)
				{
					return;
				}
			}
			__result = true;
		}
	}

	[HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")]
	private static class UpdateKnownRecipesList_Patch
	{
		private static void Prefix()
		{
			skip = true;
		}

		private static void Postfix()
		{
			skip = false;
		}
	}

	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	private static class HaveRequirements_Patch
	{
		private static void Postfix(Player __instance, ref bool __result, Piece piece, RequirementMode mode, HashSet<string> ___m_knownMaterial, Dictionary<string, int> ___m_knownStations)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Invalid comparison between Unknown and I4
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: 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_0082: Invalid comparison between Unknown and I4
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Invalid comparison between Unknown and I4
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Invalid comparison between Unknown and I4
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			bool flag2;
			if (!(!modEnabled.Value | __result) && !skip)
			{
				bool flag;
				if ((Object)(object)__instance == (Object)null)
				{
					flag = true;
				}
				else
				{
					Transform transform = ((Component)__instance).transform;
					flag = !(((Object)(object)transform != (Object)null) ? new Vector3?(transform.position) : null).HasValue;
				}
				if (!flag)
				{
					flag2 = !AllowByKey();
					goto IL_0069;
				}
			}
			flag2 = true;
			goto IL_0069;
			IL_0069:
			if (flag2)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)piece.m_craftingStation))
			{
				if ((int)mode == 1 || (int)mode == 2)
				{
					if (!___m_knownStations.ContainsKey(piece.m_craftingStation.m_name))
					{
						return;
					}
				}
				else if (!Object.op_Implicit((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position)))
				{
					return;
				}
			}
			if (piece.m_dlc.Length > 0 && !DLCMan.instance.IsDLCInstalled(piece.m_dlc))
			{
				return;
			}
			List<Container> nearbyContainers = GetNearbyContainers(((Component)__instance).transform.position);
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!Object.op_Implicit((Object)(object)val.m_resItem) || val.m_amount <= 0)
				{
					continue;
				}
				if ((int)mode == 1)
				{
					if (!___m_knownMaterial.Contains(val.m_resItem.m_itemData.m_shared.m_name))
					{
						return;
					}
				}
				else if ((int)mode == 2)
				{
					if (((Humanoid)__instance).GetInventory().HaveItem(val.m_resItem.m_itemData.m_shared.m_name, true))
					{
						continue;
					}
					bool flag3 = false;
					foreach (Container item in nearbyContainers)
					{
						if (item.GetInventory().HaveItem(val.m_resItem.m_itemData.m_shared.m_name, true))
						{
							flag3 = true;
							break;
						}
					}
					if (!flag3)
					{
						return;
					}
				}
				else
				{
					if ((int)mode != 0 || ((Humanoid)__instance).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true) >= val.m_amount)
					{
						continue;
					}
					int num = ((Humanoid)__instance).GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
					foreach (Container item2 in nearbyContainers)
					{
						try
						{
							num += item2.GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
							if (num >= val.m_amount)
							{
								break;
							}
						}
						catch
						{
						}
					}
					if (num < val.m_amount)
					{
						return;
					}
				}
			}
			__result = true;
		}
	}

	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	private static class ConsumeResources_Patch
	{
		private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled.Value || !AllowByKey())
			{
				return true;
			}
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			List<Container> nearbyContainers = GetNearbyContainers(((Component)__instance).transform.position);
			foreach (Requirement val in requirements)
			{
				if (!Object.op_Implicit((Object)(object)val.m_resItem))
				{
					continue;
				}
				int amount = val.GetAmount(qualityLevel);
				if (amount <= 0)
				{
					continue;
				}
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				int num = inventory.CountItems(name, -1, true);
				Dbgl($"have {num}/{amount} {name} in player inventory");
				inventory.RemoveItem(name, Math.Min(num, amount), -1, true);
				if (num >= amount)
				{
					continue;
				}
				foreach (Container item2 in nearbyContainers)
				{
					Inventory val2 = (((Object)(object)item2 != (Object)null) ? item2.GetInventory() : null);
					if (val2 == null)
					{
						continue;
					}
					int num2 = Mathf.Min(val2.CountItems(name, -1, true), amount - num);
					Dbgl($"Container at {((Component)item2).transform.position} has {val2.CountItems(name, -1, true)}");
					if (num2 == 0)
					{
						continue;
					}
					for (int j = 0; j < val2.GetAllItems().Count; j++)
					{
						ItemData item = val2.GetItem(j);
						string text = item?.m_shared?.m_name;
						if (text == name)
						{
							Dbgl($"Container has a total items count of {val2.GetAllItems().Count}");
							Dbgl($"Got stack of {item.m_stack} {name}");
							int num3 = Mathf.Min(item.m_stack, amount - num);
							if (num3 == item.m_stack)
							{
								val2.RemoveItem(j);
								j--;
							}
							else
							{
								item.m_stack -= num3;
							}
							num += num3;
							Dbgl($"total amount is now {num}/{amount} {name}");
							if (num >= amount)
							{
								Dbgl("Got enough, breaking");
								break;
							}
						}
					}
					Dbgl("Saving container");
					typeof(Container).GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(item2, new object[0]);
					Dbgl("Setting inventory changed");
					typeof(Inventory).GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(val2, new object[0]);
					if (num >= amount)
					{
						Dbgl("consumed enough " + name);
						break;
					}
				}
			}
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
	private static class UpdatePlacementGhost_Patch
	{
		private static void Postfix(Player __instance, bool flashGuardStone)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			if (!modEnabled.Value || !showGhostConnections.Value)
			{
				return;
			}
			FieldInfo field = typeof(Player).GetField("m_placementGhost", BindingFlags.Instance | BindingFlags.NonPublic);
			GameObject val = ((!(field != null)) ? ((GameObject)null) : ((GameObject)field.GetValue(__instance)));
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Container>() == (Object)null)
			{
				return;
			}
			FieldInfo field2 = typeof(CraftingStation).GetField("m_allStations", BindingFlags.Static | BindingFlags.NonPublic);
			List<CraftingStation> list = ((field2 != null) ? ((List<CraftingStation>)field2.GetValue(null)) : null);
			if ((Object)(object)connectionVfxPrefab == (Object)null)
			{
				GameObject[] array = Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];
				foreach (GameObject val2 in array)
				{
					if (((Object)val2).name == "vfx_ExtensionConnection")
					{
						connectionVfxPrefab = val2;
						break;
					}
				}
			}
			if ((Object)(object)connectionVfxPrefab == (Object)null || list == null)
			{
				return;
			}
			bool flag = false;
			foreach (CraftingStation item in list)
			{
				int num = ConnectionExists(item);
				bool flag2 = num != -1;
				if (Vector3.Distance(((Component)item).transform.position, val.transform.position) < m_range.Value)
				{
					flag = true;
					Vector3 connectionEffectPoint = item.GetConnectionEffectPoint();
					Vector3 val3 = val.transform.position + Vector3.up * ghostConnectionStartOffset.Value;
					ConnectionParams connectionParams;
					if (!flag2)
					{
						connectionParams = new ConnectionParams();
						connectionParams.stationPos = item.GetConnectionEffectPoint();
						connectionParams.connection = Object.Instantiate<GameObject>(connectionVfxPrefab, connectionEffectPoint, Quaternion.identity);
					}
					else
					{
						connectionParams = containerConnections[num];
					}
					if ((Object)(object)connectionParams.connection != (Object)null)
					{
						Vector3 val4 = val3 - connectionEffectPoint;
						Quaternion rotation = Quaternion.LookRotation(((Vector3)(ref val4)).normalized);
						connectionParams.connection.transform.position = connectionEffectPoint;
						connectionParams.connection.transform.rotation = rotation;
						connectionParams.connection.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref val4)).magnitude);
					}
					if (!flag2)
					{
						containerConnections.Add(connectionParams);
					}
				}
				else if (flag2)
				{
					Object.Destroy((Object)(object)containerConnections[num].connection);
					containerConnections.RemoveAt(num);
				}
			}
			if (flag && (Object)(object)context != (Object)null)
			{
				((MonoBehaviour)context).CancelInvoke("StopConnectionEffects");
				((MonoBehaviour)context).Invoke("StopConnectionEffects", ghostConnectionRemovalDelay.Value);
			}
		}
	}

	[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
	private static class DoCrafting_Patch
	{
		private static bool Prefix(InventoryGui __instance, KeyValuePair<Recipe, ItemData> ___m_selectedRecipe, ItemData ___m_craftUpgradeItem)
		{
			if (!modEnabled.Value || !AllowByKey() || !CheckKeyHeld(pullItemsKey.Value) || (Object)(object)___m_selectedRecipe.Key == (Object)null)
			{
				return true;
			}
			int num = ((___m_craftUpgradeItem == null) ? 1 : (___m_craftUpgradeItem.m_quality + 1));
			if (num > ___m_selectedRecipe.Key.m_item.m_itemData.m_shared.m_maxQuality)
			{
				return true;
			}
			Dbgl("pulling resources to player inventory for crafting item " + ___m_selectedRecipe.Key.m_item.m_itemData.m_shared.m_name);
			PullResources(Player.m_localPlayer, ___m_selectedRecipe.Key.m_resources, num);
			return false;
		}
	}

	[HarmonyPatch(typeof(Player), "UpdatePlacement")]
	private static class UpdatePlacement_Patch
	{
		private static bool Prefix(Player __instance, bool takeInput, float dt, PieceTable ___m_buildPieces, GameObject ___m_placementGhost)
		{
			if (!modEnabled.Value || !AllowByKey() || !CheckKeyHeld(pullItemsKey.Value) || !((Character)__instance).InPlaceMode() || !takeInput || Hud.IsPieceSelectionVisible())
			{
				return true;
			}
			if (ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyPlace"))
			{
				Piece selectedPiece = ___m_buildPieces.GetSelectedPiece();
				if ((Object)(object)selectedPiece != (Object)null)
				{
					if (selectedPiece.m_repairPiece)
					{
						return true;
					}
					if ((Object)(object)___m_placementGhost != (Object)null && (int)typeof(Player).GetField("m_placementStatus", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(__instance) == 0)
					{
						Dbgl("pulling resources to player inventory for piece " + ((Object)selectedPiece).name);
						PullResources(__instance, selectedPiece.m_resources, 0);
					}
				}
				return false;
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Turret), "UseItem")]
	private static class Turret_UseItem_Patch
	{
		private static void Prefix(Turret __instance, Humanoid user, ref ItemData item)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			if (!modEnabled.Value || !AllowByKey() || item != null || !(user is Player))
			{
				Dbgl($"Not allowed {AllowByKey()} {item == null} {user is Player}");
				return;
			}
			item = user.GetInventory().GetAmmoItem(__instance.m_ammoType, (__instance.GetAmmo() > 0) ? __instance.GetAmmoType() : null);
			if (item == null)
			{
				Dbgl("No item found in inventory, checking containers for " + __instance.GetAmmoType());
				GameObject prefab = ZNetScene.instance.GetPrefab(__instance.GetAmmoType());
				if (!Object.op_Implicit((Object)(object)prefab))
				{
					Dbgl("No prefab found for " + __instance.GetAmmoType());
					ZLog.LogWarning((object)("Turret '" + ((Object)__instance).name + "' is trying to fire but has no ammo or default ammo!"));
					return;
				}
				PullResources((Player)(object)((user is Player) ? user : null), (Requirement[])(object)new Requirement[1]
				{
					new Requirement
					{
						m_amount = 1,
						m_resItem = prefab.GetComponent<ItemDrop>()
					}
				}, prefab.GetComponent<ItemDrop>().m_itemData.m_quality);
			}
		}
	}

	private static class HaveRequirements_Patch2_broken
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			for (int i = 0; i < list.Count; i++)
			{
				CodeInstruction val = list[i];
				if (!(val.opcode == OpCodes.Callvirt) || !((object)val).ToString().Contains("IsDLCInstalled"))
				{
					continue;
				}
				int num = -1;
				for (int j = i + 1; j < i + 5; j++)
				{
					if (list[j].opcode == OpCodes.Ret)
					{
						num = j;
						break;
					}
				}
				if (num != -1)
				{
					int num2 = num + 1;
					List<Label> labels = list[num2].labels;
					list.RemoveRange(num2, list.Count - num2);
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)
					{
						labels = labels
					});
					list.Add(new CodeInstruction(OpCodes.Ldarg_1, (object)null));
					list.Add(new CodeInstruction(OpCodes.Ldarg_2, (object)null));
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Add(new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Humanoid), "m_inventory")));
					list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
					list.Add(new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(Player), "m_knownMaterial")));
					list.Add(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(BepInExPlugin), "HaveRequiredItemCount", (Type[])null, (Type[])null)));
					list.Add(new CodeInstruction(OpCodes.Ret, (object)null));
					break;
				}
				Dbgl(">>> FAILED to find targeted code for HaveRequirements transpiler patch!!! Mod will not work!");
			}
			return list;
		}
	}

	[HarmonyPatch(typeof(Terminal), "InputText")]
	private static class InputText_Patch
	{
		private static bool Prefix(Terminal __instance)
		{
			if (!modEnabled.Value)
			{
				return true;
			}
			string text = ((TMP_InputField)__instance.m_input).text;
			if (text.ToLower().Equals("craftfromcontainers reset"))
			{
				((BaseUnityPlugin)context).Config.Reload();
				((BaseUnityPlugin)context).Config.Save();
				__instance.AddString(text);
				__instance.AddString("Craft From Containers config reloaded");
				return false;
			}
			return true;
		}
	}

	private static bool wasAllowed;

	private static List<ConnectionParams> containerConnections;

	private static GameObject connectionVfxPrefab;

	public static ConfigEntry<bool> showGhostConnections;

	public static ConfigEntry<float> ghostConnectionStartOffset;

	public static ConfigEntry<float> ghostConnectionRemovalDelay;

	public static ConfigEntry<float> m_range;

	public static ConfigEntry<Color> flashColor;

	public static ConfigEntry<Color> unFlashColor;

	public static ConfigEntry<string> resourceString;

	public static ConfigEntry<string> pulledMessage;

	public static ConfigEntry<string> fuelDisallowTypes;

	public static ConfigEntry<string> oreDisallowTypes;

	public static ConfigEntry<string> pullItemsKey;

	public static ConfigEntry<string> preventModKey;

	public static ConfigEntry<string> fillAllModKey;

	public static ConfigEntry<bool> switchPrevent;

	public static ConfigEntry<bool> ignoreShipContainers;

	public static ConfigEntry<bool> ignoreWagonContainers;

	public static ConfigEntry<bool> ignoreWoodChests;

	public static ConfigEntry<bool> ignorePrivateChests;

	public static ConfigEntry<bool> ignoreBlackMetalChests;

	public static ConfigEntry<bool> ignoreReinforcedChests;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<bool> isDebug;

	public static ConfigEntry<int> nexusID;

	public static List<Container> containerList;

	public static bool odinsQolInstalled;

	public static float itemStackSizeMultiplier;

	public static float itemWeightReduction;

	public static Vector3 lastPosition;

	public static List<Container> cachedContainerList;

	private static BepInExPlugin context;

	private static bool skip;

	public static void Dbgl(string str = "", bool pref = true)
	{
		if (isDebug.Value)
		{
			((BaseUnityPlugin)context).Logger.Log((LogLevel)32, (object)((pref ? (typeof(BepInExPlugin).Namespace + " ") : "") + str));
		}
	}

	private void Awake()
	{
		//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		context = this;
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
		isDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IsDebug", true, "Show debug messages in log");
		nexusID = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 40, "Nexus mod ID for updates");
		m_range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ContainerRange", 10f, "The maximum range from which to pull items from");
		resourceString = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ResourceCostString", "{0}/{1}", "String used to show required and available resources. {0} is replaced by how much is available, and {1} is replaced by how much is required. Set to nothing to leave it as default.");
		flashColor = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "FlashColor", Color.yellow, "Resource amounts will flash to this colour when coming from containers");
		unFlashColor = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "UnFlashColor", Color.white, "Resource amounts will flash from this colour when coming from containers (set both colors to the same color for no flashing)");
		pulledMessage = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PulledMessage", "Pulled items to inventory", "Message to show after pulling items to player inventory");
		fuelDisallowTypes = ((BaseUnityPlugin)this).Config.Bind<string>("General", "FuelDisallowTypes", "RoundLog,FineWood", "Types of item to disallow as fuel (i.e. anything that is consumed), comma-separated.");
		oreDisallowTypes = ((BaseUnityPlugin)this).Config.Bind<string>("General", "OreDisallowTypes", "RoundLog,FineWood", "Types of item to disallow as ore (i.e. anything that is transformed), comma-separated).");
		showGhostConnections = ((BaseUnityPlugin)this).Config.Bind<bool>("Station Connections", "ShowConnections", false, "If true, will display connections to nearby workstations within range when building containers");
		ghostConnectionStartOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Station Connections", "ConnectionStartOffset", 1.25f, "Height offset for the connection VFX start position");
		ghostConnectionRemovalDelay = ((BaseUnityPlugin)this).Config.Bind<float>("Station Connections", "ConnectionRemoveDelay", 0.05f, "");
		switchPrevent = ((BaseUnityPlugin)this).Config.Bind<bool>("Hot Keys", "SwitchPrevent", false, "if true, holding down the PreventModKey modifier key will allow this mod's behaviour; if false, holding down the key will prevent it.");
		preventModKey = ((BaseUnityPlugin)this).Config.Bind<string>("Hot Keys", "PreventModKey", "left alt", "Modifier key to toggle fuel and ore filling behaviour when down. Use https://docs.unity3d.com/Manual/ConventionalGameInput.html");
		pullItemsKey = ((BaseUnityPlugin)this).Config.Bind<string>("Hot Keys", "PullItemsKey", "left ctrl", "Holding down this key while crafting or building will pull resources into your inventory instead of building. Use https://docs.unity3d.com/Manual/ConventionalGameInput.html");
		fillAllModKey = ((BaseUnityPlugin)this).Config.Bind<string>("Hot Keys", "FillAllModKey", "left shift", "Modifier key to pull all available fuel or ore when down. Use https://docs.unity3d.com/Manual/ConventionalGameInput.html");
		ignoreShipContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnoreShipContainers", false, "If true, will ignore this type of container.");
		ignoreWagonContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnoreWagonContainers", false, "If true, will ignore this type of container.");
		ignoreWoodChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnoreWoodChests", false, "If true, will ignore this type of container.");
		ignorePrivateChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnorePrivateChests", false, "If true, will ignore this type of container.");
		ignoreBlackMetalChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnoreBlackMetalChests", false, "If true, will ignore this type of container.");
		ignoreReinforcedChests = ((BaseUnityPlugin)this).Config.Bind<bool>("Container Types", "IgnoreReinforcedChests", false, "If true, will ignore this type of container.");
		wasAllowed = !switchPrevent.Value;
		Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
		Dbgl("Mod awake");
	}

	private void LateUpdate()
	{
		wasAllowed = AllowByKey();
		skip = false;
	}

	private static bool AllowByKey()
	{
		if (CheckKeyHeld(preventModKey.Value))
		{
			return switchPrevent.Value;
		}
		return !switchPrevent.Value;
	}

	private void OnDestroy()
	{
		StopConnectionEffects();
	}

	private static bool CheckKeyHeld(string value, bool req = true)
	{
		try
		{
			return Input.GetKey(value.ToLower());
		}
		catch
		{
			return !req;
		}
	}

	public static List<Container> GetNearbyContainers(Vector3 center)
	{
		//IL_001a: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0116: Unknown result type (might be due to invalid IL or missing references)
		List<Container> list = new List<Container>();
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return list;
		}
		if (Vector3.Distance(center, lastPosition) < 0.5f)
		{
			return cachedContainerList;
		}
		MethodInfo methodInfo = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);
		foreach (Container container in containerList)
		{
			if ((Object)(object)container != (Object)null && (Object)(object)((Component)container).transform != (Object)null && (m_range.Value <= 0f || Vector3.Distance(center, ((Component)container).transform.position) < m_range.Value) && AllowContainerType(container) && (bool)methodInfo.Invoke(container, new object[1] { Player.m_localPlayer.GetPlayerID() }) && !container.IsInUse() && (Object)(object)((Component)container).GetComponentInParent<Piece>() != (Object)null && container.GetInventory() != null && (!container.m_checkGuardStone || PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)))
			{
				list.Add(container);
			}
		}
		Dbgl($"Got {list.Count} containers.");
		lastPosition = center;
		cachedContainerList = list;
		return list;
	}

	private static bool AllowContainerType(Container __instance)
	{
		Transform parent = ((Component)__instance).gameObject.transform.parent;
		Ship val = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent<Ship>() : null);
		if ((!ignoreShipContainers.Value || (Object)(object)val == (Object)null) && (!ignoreWagonContainers.Value || (Object)(object)__instance.m_wagon == (Object)null) && (!ignoreWoodChests.Value || !((Object)__instance).name.StartsWith("piece_chest_wood(")) && (!ignorePrivateChests.Value || !((Object)__instance).name.StartsWith("piece_chest_private(")) && (!ignoreBlackMetalChests.Value || !((Object)__instance).name.StartsWith("piece_chest_blackmetal(")))
		{
			if (ignoreReinforcedChests.Value)
			{
				return !((Object)__instance).name.StartsWith("piece_chest(");
			}
			return true;
		}
		return false;
	}

	public static IEnumerator AddContainer(Container container, ZNetView nview)
	{
		yield return null;
		try
		{
			if (container.GetInventory() != null && (((Object)(object)nview != (Object)null) ? nview.GetZDO() : null) != null && (((Object)container).name.StartsWith("piece_") || ((Object)container).name.StartsWith("Container") || nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0L))
			{
				Dbgl("Adding " + ((Object)container).name);
				containerList.Add(container);
			}
		}
		catch
		{
		}
	}

	public static int ConnectionExists(CraftingStation station)
	{
		//IL_0016: 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)
		foreach (ConnectionParams containerConnection in containerConnections)
		{
			if (Vector3.Distance(containerConnection.stationPos, station.GetConnectionEffectPoint()) < 0.1f)
			{
				return containerConnections.IndexOf(containerConnection);
			}
		}
		return -1;
	}

	public void StopConnectionEffects()
	{
		if (containerConnections.Count > 0)
		{
			foreach (ConnectionParams containerConnection in containerConnections)
			{
				Object.Destroy((Object)(object)containerConnection.connection);
			}
		}
		containerConnections.Clear();
	}

	private static void PullResources(Player player, Requirement[] resources, int qualityLevel)
	{
		//IL_0015: 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)
		Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory();
		List<Container> nearbyContainers = GetNearbyContainers(((Component)Player.m_localPlayer).transform.position);
		foreach (Requirement val in resources)
		{
			if (Object.op_Implicit((Object)(object)val.m_resItem))
			{
				int amount = val.GetAmount(qualityLevel);
				if (amount <= 0)
				{
					continue;
				}
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				int num = 0;
				foreach (Container item2 in nearbyContainers)
				{
					Inventory inventory2 = item2.GetInventory();
					int num2 = Mathf.Min(inventory2.CountItems(name, -1, true), amount - num);
					Dbgl($"Container at {((Component)item2).transform.position} has {inventory2.CountItems(name, -1, true)}");
					if (num2 == 0)
					{
						continue;
					}
					for (int j = 0; j < inventory2.GetAllItems().Count; j++)
					{
						ItemData item = inventory2.GetItem(j);
						if (!(item.m_shared.m_name == name))
						{
							continue;
						}
						Dbgl($"Got stack of {item.m_stack} {name}");
						int num3 = Mathf.Min(item.m_stack, amount - num);
						if (!inventory.HaveEmptySlot())
						{
							num3 = Math.Min(Traverse.Create((object)inventory).Method("FindFreeStackSpace", new object[1] { item.m_shared.m_name }).GetValue<int>(), num3);
						}
						Dbgl($"Sending {num3} {name} to player");
						ItemData val2 = item.Clone();
						val2.m_stack = num3;
						if (odinsQolInstalled)
						{
							if (itemStackSizeMultiplier > 0f)
							{
								val2.m_shared.m_weight = ApplyModifierValue(val2.m_shared.m_weight, itemWeightReduction);
								if (val2.m_shared.m_maxStackSize > 1 && itemStackSizeMultiplier >= 1f)
								{
									val2.m_shared.m_maxStackSize = (int)ApplyModifierValue(val.m_resItem.m_itemData.m_shared.m_maxStackSize, itemStackSizeMultiplier);
								}
							}
						}
						else
						{
							val2.m_shared.m_maxStackSize = val.m_resItem.m_itemData.m_shared.m_maxStackSize;
						}
						inventory.AddItem(val2);
						if (num3 == item.m_stack)
						{
							inventory2.RemoveItem(j);
						}
						else
						{
							item.m_stack -= num3;
						}
						num += num3;
						Dbgl($"total amount is now {num}/{amount} {name}");
						if (num >= amount)
						{
							break;
						}
					}
					((object)item2).GetType().GetMethod("Save", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(item2, new object[0]);
					((object)inventory2).GetType().GetMethod("Changed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(inventory2, new object[0]);
					if (num >= amount)
					{
						Dbgl("pulled enough " + name);
						break;
					}
				}
			}
			string value = pulledMessage.Value;
			if (value != null && value.Length > 0)
			{
				((Character)player).Message((MessageType)2, pulledMessage.Value, 0, (Sprite)null);
			}
		}
	}

	public static bool HaveRequiredItemCount(Player player, Piece piece, RequirementMode mode, Inventory inventory, HashSet<string> knownMaterial)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected I4, but got Unknown
		List<Container> nearbyContainers = GetNearbyContainers(((Component)player).transform.position);
		Requirement[] resources = piece.m_resources;
		foreach (Requirement val in resources)
		{
			if (!Object.op_Implicit((Object)(object)val.m_resItem) || val.m_amount <= 0)
			{
				continue;
			}
			switch ((int)mode)
			{
			case 0:
			{
				int num = inventory.CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
				if (num >= val.m_amount)
				{
					break;
				}
				bool flag2 = false;
				foreach (Container item in nearbyContainers)
				{
					try
					{
						num += item.GetInventory().CountItems(val.m_resItem.m_itemData.m_shared.m_name, -1, true);
						if (num >= val.m_amount)
						{
							flag2 = true;
							break;
						}
					}
					catch
					{
					}
				}
				if (!flag2)
				{
					return false;
				}
				break;
			}
			case 1:
				if (!knownMaterial.Contains(val.m_resItem.m_itemData.m_shared.m_name))
				{
					return false;
				}
				break;
			case 2:
			{
				if (inventory.HaveItem(val.m_resItem.m_itemData.m_shared.m_name, true))
				{
					break;
				}
				bool flag = false;
				foreach (Container item2 in nearbyContainers)
				{
					if (item2.GetInventory().HaveItem(val.m_resItem.m_itemData.m_shared.m_name, true))
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					return false;
				}
				break;
			}
			}
		}
		return true;
	}

	public static void CheckOdinsQOLConfig()
	{
		itemStackSizeMultiplier = 0f;
		itemWeightReduction = 0f;
		foreach (PluginInfo value in Chainloader.PluginInfos.Values)
		{
			if (!(((value != null) ? value.Metadata.GUID : null) == "com.odinplusqol.mod"))
			{
				continue;
			}
			odinsQolInstalled = modEnabled.Value;
			Debug.Log((object)"Found OdinPlusQoL");
			foreach (ConfigDefinition key in value.Instance.Config.Keys)
			{
				if (key.Key == "Item Stack Increase")
				{
					itemStackSizeMultiplier = (float)value.Instance.Config[key].BoxedValue;
				}
				if (key.Key == "Item Weight Increase")
				{
					itemWeightReduction = (float)value.Instance.Config[key].BoxedValue;
				}
			}
		}
	}

	public static float ApplyModifierValue(float targetValue, float value)
	{
		if (value <= -100f)
		{
			value = -100f;
		}
		if (value >= 0f)
		{
			return targetValue + targetValue / 100f * value;
		}
		return targetValue - targetValue / 100f * (value * -1f);
	}

	static BepInExPlugin()
	{
		//IL_001a: 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)
		containerConnections = new List<ConnectionParams>();
		connectionVfxPrefab = null;
		containerList = new List<Container>();
		lastPosition = Vector3.positiveInfinity;
		cachedContainerList = new List<Container>();
		context = null;
	}
}