Decompiled source of ItemHopper Valheim1Compat v1.0.1

plugins/ItemHopper_Valheim1Compat/ValheimHopper.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.GUI;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using MultiUserChest;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using ValheimHopper.Logic;
using ValheimHopper.Logic.Helper;
using ValheimHopper.UI;
using ValheimPipes;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimPipes")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimPipes")]
[assembly: AssemblyCopyright("Copyright \ufffd  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("FE8B42E3-7082-4DFF-A5CC-6B62B0315ACA")]
[assembly: AssemblyFileVersion("1.0.1")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimHopper.UI
{
	public class HopperUI : MonoBehaviour
	{
		private static readonly Color WhiteShade = new Color(73f / 85f, 73f / 85f, 73f / 85f);

		[SerializeField]
		private Text title;

		[SerializeField]
		private Toggle filterHopper;

		[SerializeField]
		private Toggle dropItems;

		[SerializeField]
		private Toggle pickupItems;

		[SerializeField]
		private Toggle leaveLastItem;

		private Toggle blacklistMode;

		private Toggle stackMode;

		[SerializeField]
		private Button copyButton;

		[SerializeField]
		private Button pasteButton;

		[SerializeField]
		private Button resetButton;

		private static GameObject uiRoot;

		private Hopper target;

		private Hopper copy;

		public static HopperUI Instance { get; private set; }

		public static bool IsOpen { get; private set; }

		private void Awake()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			Instance = this;
			((UnityEvent<bool>)(object)dropItems.onValueChanged).AddListener((UnityAction<bool>)delegate(bool i)
			{
				if ((Object)(object)target != (Object)null)
				{
					target.DropItemsOption.Set(i);
				}
			});
			((UnityEvent<bool>)(object)pickupItems.onValueChanged).AddListener((UnityAction<bool>)delegate(bool i)
			{
				if ((Object)(object)target != (Object)null)
				{
					target.PickupItemsOption.Set(i);
				}
			});
			((UnityEvent<bool>)(object)leaveLastItem.onValueChanged).AddListener((UnityAction<bool>)delegate(bool i)
			{
				if ((Object)(object)target != (Object)null)
				{
					target.LeaveLastItemOption.Set(i);
				}
			});
			((UnityEvent<bool>)(object)filterHopper.onValueChanged).AddListener((UnityAction<bool>)delegate(bool active)
			{
				if (!((Object)(object)target == (Object)null))
				{
					target.FilterItemsOption.Set(active);
					if (active)
					{
						target.filter.Save();
					}
					else
					{
						target.filter.Clear();
					}
				}
			});
			((UnityEvent)copyButton.onClick).AddListener((UnityAction)delegate
			{
				if ((Object)(object)target != (Object)null)
				{
					copy = target;
				}
			});
			((UnityEvent)pasteButton.onClick).AddListener((UnityAction)delegate
			{
				if ((Object)(object)target != (Object)null && (Object)(object)copy != (Object)null && copy.IsValid())
				{
					target.PasteData(copy);
				}
			});
			((UnityEvent)resetButton.onClick).AddListener((UnityAction)delegate
			{
				if ((Object)(object)target != (Object)null)
				{
					target.ResetValues();
				}
			});
		}

		private void SetupNewToggles()
		{
			((UnityEvent<bool>)(object)blacklistMode.onValueChanged).AddListener((UnityAction<bool>)delegate(bool i)
			{
				if ((Object)(object)target != (Object)null)
				{
					target.BlacklistModeOption.Set(i);
				}
			});
			((UnityEvent<bool>)(object)stackMode.onValueChanged).AddListener((UnityAction<bool>)delegate(bool i)
			{
				if ((Object)(object)target != (Object)null)
				{
					target.StackModeOption.Set(i);
				}
			});
		}

		public static void Init()
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(Plugin.AssetBundle.LoadAsset<GameObject>("HopperUI"), GUIManager.CustomGUIFront.transform, false);
			uiRoot = ((Component)obj.transform.GetChild(0)).gameObject;
			HopperUI component = obj.GetComponent<HopperUI>();
			if ((Object)(object)component == (Object)null)
			{
				Logger.LogWarning((object)"HopperUI component missing on prefab! If you renamed the namespace, you must restore it to ValheimHopper.UI for AssetBundle compatibility.");
				uiRoot.SetActive(false);
				return;
			}
			ApplyAllComponents(uiRoot);
			GUIManager.Instance.ApplyTextStyle(component.title, GUIManager.Instance.AveriaSerifBold, GUIManager.Instance.ValheimOrange, 20, true);
			ApplyLocalization();
			component.blacklistMode = CreateToggle(component.filterHopper, "BlacklistMode", "$hopper_options_blacklist", new Vector2(0f, -110f));
			component.stackMode = CreateToggle(component.filterHopper, "StackMode", "$hopper_options_stack", new Vector2(0f, -140f));
			component.SetupNewToggles();
			uiRoot.AddComponent<DragWindowCntrl>();
			uiRoot.SetActive(false);
			PrefabExtension.FixReferences(uiRoot, true);
		}

		private void LateUpdate()
		{
			if (!Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				target = null;
				SetGUIState(active: false);
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			Hopper hopper = default(Hopper);
			if (!Object.op_Implicit((Object)(object)instance) || !instance.IsContainerOpen() || !Object.op_Implicit((Object)(object)instance.m_currentContainer))
			{
				target = null;
				SetGUIState(active: false);
			}
			else if (((Component)instance.m_currentContainer).TryGetComponent<Hopper>(ref hopper))
			{
				target = hopper;
				SetGUIState(active: true);
				UpdateText();
			}
			else
			{
				target = null;
				SetGUIState(active: false);
			}
		}

		private static void SetGUIState(bool active)
		{
			if (IsOpen != active)
			{
				IsOpen = active;
				uiRoot.SetActive(active);
			}
		}

		private void UpdateText()
		{
			title.text = Localization.instance.Localize(target.Piece.m_name);
			filterHopper.SetIsOnWithoutNotify(target.FilterItemsOption.Get());
			dropItems.SetIsOnWithoutNotify(target.DropItemsOption.Get());
			pickupItems.SetIsOnWithoutNotify(target.PickupItemsOption.Get());
			leaveLastItem.SetIsOnWithoutNotify(target.LeaveLastItemOption.Get());
			blacklistMode.SetIsOnWithoutNotify(target.BlacklistModeOption.Get());
			stackMode.SetIsOnWithoutNotify(target.StackModeOption.Get());
			bool active = ((Object)target).name.Contains("Iron");
			((Component)stackMode).gameObject.SetActive(active);
		}

		private static void ApplyAllComponents(GameObject root)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Text[] componentsInChildren = root.GetComponentsInChildren<Text>();
			foreach (Text val in componentsInChildren)
			{
				GUIManager.Instance.ApplyTextStyle(val, GUIManager.Instance.AveriaSerif, WhiteShade, 16, false);
			}
			InputField[] componentsInChildren2 = root.GetComponentsInChildren<InputField>();
			foreach (InputField val2 in componentsInChildren2)
			{
				GUIManager.Instance.ApplyInputFieldStyle(val2, 16);
			}
			Toggle[] componentsInChildren3 = root.GetComponentsInChildren<Toggle>();
			foreach (Toggle val3 in componentsInChildren3)
			{
				GUIManager.Instance.ApplyToogleStyle(val3);
			}
			Button[] componentsInChildren4 = root.GetComponentsInChildren<Button>();
			foreach (Button val4 in componentsInChildren4)
			{
				GUIManager.Instance.ApplyButtonStyle(val4, 16);
			}
		}

		private static void ApplyLocalization()
		{
			Text[] componentsInChildren = uiRoot.GetComponentsInChildren<Text>();
			foreach (Text val in componentsInChildren)
			{
				val.text = Localization.instance.Localize(val.text);
			}
		}

		private static Toggle CreateToggle(Toggle source, string name, string label, Vector2 offset)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Toggle val = Object.Instantiate<Toggle>(source, ((Component)source).transform.parent);
			((Object)val).name = name;
			Transform transform = ((Component)val).transform;
			transform.localPosition += Vector2.op_Implicit(offset);
			((Component)val).GetComponentInChildren<Text>().text = Localization.instance.Localize(label);
			GUIManager.Instance.ApplyToogleStyle(val);
			return val;
		}
	}
}
namespace ValheimHopper.Logic
{
	[DefaultExecutionOrder(5)]
	public class Hopper : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>, IPullTarget
	{
		private Container container;

		private ContainerTarget containerTarget;

		[SerializeField]
		private Vector3 inPos = new Vector3(0f, 0.375f, 0f);

		[SerializeField]
		private Vector3 outPos = new Vector3(0f, -0.375f, 0f);

		[SerializeField]
		private Vector3 inSize = new Vector3(1f, 0.5f, 1f);

		[SerializeField]
		private Vector3 outSize = new Vector3(1f, 1f, 1f);

		private List<IPushTarget> pushTo = new List<IPushTarget>();

		internal List<IPullTarget> pullFrom = new List<IPullTarget>();

		private BoxVisualizer inVisualizer;

		private BoxVisualizer outVisualizer;

		private int lastPullFrame = -1;

		private const float ObjectSearchInterval = 3f;

		private int transferFrame;

		private int objectSearchFrame;

		private int frameOffset;

		private int pullCounter;

		public ItemFilter filter;

		public Piece Piece { get; private set; }

		public HopperPriority PushPriority { get; } = HopperPriority.HopperPull;

		public HopperPriority PullPriority { get; } = HopperPriority.HopperPull;

		public bool IsPickup { get; }

		public Vector3 InPos => inPos;

		public Vector3 InSize => inSize;

		public ZBool FilterItemsOption { get; private set; }

		public ZBool BlacklistModeOption { get; private set; }

		public ZBool StackModeOption { get; private set; }

		public ZBool DropItemsOption { get; private set; }

		public ZBool PickupItemsOption { get; private set; }

		public ZBool LeaveLastItemOption { get; private set; }

		private string DbgId
		{
			get
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				Vector3 position = ((Component)this).transform.position;
				return "Hopper@" + ((Vector3)(ref position)).ToString("F1");
			}
		}

		protected override void Awake()
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: 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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			base.Awake();
			Piece = ((Component)this).GetComponent<Piece>();
			container = ((Component)this).GetComponent<Container>();
			containerTarget = ((Component)this).GetComponent<ContainerTarget>();
			FilterItemsOption = new ZBool("hopper_filter_items", defaultValue: false, zNetView);
			BlacklistModeOption = new ZBool("hopper_blacklist_mode", defaultValue: false, zNetView);
			StackModeOption = new ZBool("hopper_stack_mode", defaultValue: false, zNetView);
			DropItemsOption = new ZBool("hopper_drop_items", defaultValue: false, zNetView);
			PickupItemsOption = new ZBool("hopper_pickup_items", defaultValue: true, zNetView);
			LeaveLastItemOption = new ZBool("hopper_leave_last_item", defaultValue: false, zNetView);
			UpdateTransferRate();
			objectSearchFrame = Mathf.RoundToInt(1f / Time.fixedDeltaTime * 3f);
			frameOffset = Mathf.Abs(((Object)this).GetInstanceID() % transferFrame);
			inVisualizer = ((Component)this).gameObject.AddComponent<BoxVisualizer>();
			inVisualizer.SetData(inPos, inSize, Color.blue, Plugin.ShowHopperInputBox);
			outVisualizer = ((Component)this).gameObject.AddComponent<BoxVisualizer>();
			outVisualizer.SetData(outPos, outSize, Color.yellow, Plugin.ShowHopperOutputBox);
		}

		private void UpdateTransferRate()
		{
			float num = (((Object)this).name.Contains("Iron") ? Plugin.IronTransferRate.Value : Plugin.BronzeTransferRate.Value);
			float num2 = 30f / Mathf.Max(1f, num);
			transferFrame = Mathf.RoundToInt(num2 / Time.fixedDeltaTime);
			if (transferFrame < 1)
			{
				transferFrame = 1;
			}
		}

		private void Start()
		{
			filter = new ItemFilter(zNetView, container.GetInventory());
			Inventory inventory = container.GetInventory();
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged));
			HopperHelper.OnTargetChanged += OnTargetChanged;
		}

		private void OnDestroy()
		{
			HopperHelper.OnTargetChanged -= OnTargetChanged;
		}

		private void OnInventoryChanged()
		{
			WakeUp();
			if (IsValid() && FilterItemsOption.Get())
			{
				filter.Save();
			}
		}

		private void OnTargetChanged(ITarget target)
		{
			if (base.IsPushBlocked && pushTo.Any((IPushTarget t) => t.NetworkHashCode() == target.NetworkHashCode()))
			{
				base.IsPushBlocked = false;
			}
			if (base.IsPullBlocked && pullFrom.Any((IPullTarget t) => t.NetworkHashCode() == target.NetworkHashCode()))
			{
				base.IsPullBlocked = false;
			}
		}

		public void PasteData(Hopper copy)
		{
			FilterItemsOption.Set(copy.FilterItemsOption.Get());
			BlacklistModeOption.Set(copy.BlacklistModeOption.Get());
			StackModeOption.Set(copy.StackModeOption.Get());
			DropItemsOption.Set(copy.DropItemsOption.Get());
			PickupItemsOption.Set(copy.PickupItemsOption.Get());
			LeaveLastItemOption.Set(copy.LeaveLastItemOption.Get());
			filter.Copy(copy.filter);
		}

		public void ResetValues()
		{
			FilterItemsOption.Reset();
			BlacklistModeOption.Reset();
			StackModeOption.Reset();
			DropItemsOption.Reset();
			PickupItemsOption.Reset();
			LeaveLastItemOption.Reset();
			filter.Clear();
		}

		private void FixedUpdate()
		{
			if (!IsValid() || !zNetView.IsOwner() || Plugin.DisableAllSystems.Value)
			{
				return;
			}
			int fixedFrameCount = HopperHelper.GetFixedFrameCount();
			int num = (fixedFrameCount + frameOffset) / transferFrame;
			if ((fixedFrameCount + frameOffset) % transferFrame == 0)
			{
				if (num % 2 == 0 && !base.IsPullBlocked)
				{
					PullItems();
				}
				if (num % 2 == 1 && !base.IsPushBlocked)
				{
					PushItems();
				}
			}
			if ((fixedFrameCount + frameOffset + 1) % objectSearchFrame == 0)
			{
				FindIO();
			}
		}

		private void PullItems()
		{
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			if (pullFrom.Count == 0)
			{
				base.IsPullBlocked = true;
				return;
			}
			int num = pullCounter % pullFrom.Count;
			IPullTarget pullTarget = pullFrom[num];
			pullCounter++;
			if (!pullTarget.IsValid())
			{
				Plugin.Debug($"[{DbgId}] Pull source [{num}] invalid, skipping");
			}
			else
			{
				if (!PickupItemsOption.Get() && pullTarget.IsPickup)
				{
					return;
				}
				foreach (ItemData item in pullTarget.GetItems())
				{
					if (!FindFreeSlot(item, out var pos))
					{
						Plugin.Debug($"[{DbgId}] No free slot for '{item.m_shared.m_name}' from source [{num}]");
						base.IsPullBlocked = true;
						continue;
					}
					int num2 = 1;
					if (StackModeOption.Get() && ((Object)this).name.Contains("Iron"))
					{
						int maxStackSize = item.m_shared.m_maxStackSize;
						int stack = item.m_stack;
						int roomForItem = container.GetInventory().GetRoomForItem(item);
						num2 = Mathf.Min(new int[3] { maxStackSize, stack, roomForItem });
					}
					object[] obj = new object[6]
					{
						DbgId,
						num2,
						item.m_shared.m_name,
						pullTarget.GetType().Name,
						null,
						null
					};
					IPullTarget obj2 = ((pullTarget is MonoBehaviour) ? pullTarget : null);
					obj[4] = ((obj2 != null) ? ((Object)((Component)obj2).gameObject).name : null);
					obj[5] = pullCounter;
					Plugin.Debug(string.Format("[{0}] Pulling {1}x '{2}' <- {3} ({4}) (counter={5})", obj));
					pullTarget.RemoveItem(item, container.GetInventory(), pos, zNetView.m_zdo.m_uid, num2);
					HopperHelper.NotifyChange(this);
					HopperHelper.NotifyChange(pullTarget);
					return;
				}
				base.IsPullBlocked = true;
			}
		}

		private void PushItems()
		{
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			if (pushTo.Count == 0)
			{
				if (DropItemsOption.Get())
				{
					DropItem();
				}
				else
				{
					base.IsPushBlocked = true;
				}
				return;
			}
			int num = OutputCounter % pushTo.Count;
			IPushTarget to = pushTo[num];
			OutputCounter++;
			if (!to.IsValid())
			{
				Plugin.Debug($"[{DbgId}] Push target [{num}] invalid, skipping");
				return;
			}
			ItemData val = container.GetInventory().FindLastItem((ItemData i) => to.CanAddItem(i) && CanPushItem(i));
			if (val != null)
			{
				int num2 = 1;
				if (StackModeOption.Get() && ((Object)this).name.Contains("Iron"))
				{
					int maxStackSize = val.m_shared.m_maxStackSize;
					int num3 = container.GetInventory().CountItems(val.m_shared.m_name, -1, true);
					if (LeaveLastItemOption.Get())
					{
						num3--;
					}
					num2 = Mathf.Min(maxStackSize, num3);
				}
				object[] obj = new object[6]
				{
					DbgId,
					num2,
					val.m_shared.m_name,
					to.GetType().Name,
					null,
					null
				};
				IPushTarget pushTarget = to;
				IPushTarget obj2 = ((pushTarget is MonoBehaviour) ? pushTarget : null);
				obj[4] = ((obj2 != null) ? ((Object)((Component)obj2).gameObject).name : null);
				obj[5] = OutputCounter;
				Plugin.Debug(string.Format("[{0}] Pushing {1}x '{2}' -> {3} ({4}) (counter={5})", obj));
				to.AddItem(val, container.GetInventory(), zNetView.m_zdo.m_uid, num2);
				HopperHelper.NotifyChange(this);
				HopperHelper.NotifyChange(to);
			}
			else
			{
				Plugin.Debug($"[{DbgId}] No pushable item for target [{num}] ({to.GetType().Name}) (full, filtered, or leave-last)");
				base.IsPushBlocked = true;
			}
		}

		private void DropItem()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = container.GetInventory().FindLastItem(CanPushItem);
			if (val != null)
			{
				container.GetInventory().RemoveOneItem(val);
				float num = Random.Range(0f, (float)Math.PI * 2f);
				Vector3 val2 = new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * 0.2f;
				Vector3 visualItemOffset = ItemHelper.GetVisualItemOffset(((Object)val.m_dropPrefab).name);
				Vector3 val3 = ((Component)this).transform.TransformPoint(outPos) + visualItemOffset + new Vector3(val2.x, 0f, val2.z);
				ItemDrop.DropItem(val, 1, val3, val.m_dropPrefab.transform.rotation);
			}
		}

		public bool CanAddItem(ItemData item)
		{
			Vector2i pos;
			return FindFreeSlot(item, out pos);
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			//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)
			FindFreeSlot(item, out var pos);
			ContainerHandler.AddItemToChest(container, item, source, pos, sender, amount);
		}

		public IEnumerable<ItemData> GetItems()
		{
			if (HopperHelper.GetFixedFrameCount() == lastPullFrame)
			{
				return Enumerable.Empty<ItemData>();
			}
			return containerTarget.GetItems();
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Debug("[" + DbgId + "] RemoveItem '" + item.m_shared.m_name + "' pulled by upstream");
			lastPullFrame = HopperHelper.GetFixedFrameCount();
			containerTarget.RemoveItem(item, destination, destinationPos, sender, amount);
		}

		private bool FindFreeSlot(ItemData itemToAdd, out Vector2i pos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			pos = new Vector2i(0, 0);
			if (!container.GetInventory().CanAddItem(itemToAdd, 1))
			{
				return false;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)itemToAdd.m_dropPrefab).name);
			for (int i = 0; i < container.m_height; i++)
			{
				for (int j = 0; j < container.m_width; j++)
				{
					ItemData itemAt = container.GetInventory().GetItemAt(j, i);
					if (itemAt != null && (itemAt.m_stack + 1 > itemAt.m_shared.m_maxStackSize || !(itemAt.m_shared.m_name == itemToAdd.m_shared.m_name)))
					{
						continue;
					}
					if (FilterItemsOption.Get())
					{
						if (BlacklistModeOption.Get())
						{
							if (filter.Contains(stableHashCode))
							{
								return false;
							}
							pos = new Vector2i(j, i);
							return true;
						}
						int itemHash = filter.GetItemHash(j, i);
						if (itemHash == 0 || itemHash == stableHashCode)
						{
							pos = new Vector2i(j, i);
							return true;
						}
						continue;
					}
					pos = new Vector2i(j, i);
					return true;
				}
			}
			return false;
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		private bool CanPushItem(ItemData item)
		{
			if (LeaveLastItemOption.Get())
			{
				return container.GetInventory().CountItems(item.m_shared.m_name, -1, true) > 1;
			}
			return true;
		}

		private void FindIO()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			Quaternion rotation = ((Component)this).transform.rotation;
			pullFrom = HopperHelper.FindTargets(((Component)this).transform.TransformPoint(inPos), inSize, rotation, (IPullTarget i) => i.PullPriority, this);
			int count = pullFrom.Count;
			pullFrom.RemoveAll((IPullTarget i) => i is Pipe);
			if (pullFrom.Count < count)
			{
				Plugin.Debug($"[{DbgId}] Ignored {count - pullFrom.Count} Upstream Pipes (Hoppers cannot pull from Pipes)");
			}
			pushTo = HopperHelper.FindTargets(((Component)this).transform.TransformPoint(outPos), outSize, rotation, (IPushTarget i) => i.PushPriority, this);
			Plugin.Debug(string.Format("[{0}] Targets: Pull[{1}] {2}", DbgId, pullFrom.Count, string.Join(", ", pullFrom.Select(delegate(IPullTarget t)
			{
				IPullTarget obj = ((t is MonoBehaviour) ? t : null);
				return ((obj != null) ? ((Object)((Component)obj).gameObject).name : null) ?? t.GetType().Name;
			}))));
			Plugin.Debug(string.Format("[{0}] Targets: Push[{1}] {2}", DbgId, pushTo.Count, string.Join(", ", pushTo.Select(delegate(IPushTarget t)
			{
				IPushTarget obj = ((t is MonoBehaviour) ? t : null);
				return ((obj != null) ? ((Object)((Component)obj).gameObject).name : null) ?? t.GetType().Name;
			}))));
			pullFrom.RemoveAll((IPullTarget pull) => pushTo.Exists((IPushTarget push) => push.NetworkHashCode() == pull.NetworkHashCode()));
			WakeUp();
		}

		private void OnDrawGizmos()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0070: Expected O, but got Unknown
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			Gizmos.color = Color.blue;
			Gizmos.DrawWireCube(((Component)this).transform.TransformPoint(inPos), inSize);
			Gizmos.color = Color.yellow;
			Gizmos.DrawWireCube(((Component)this).transform.TransformPoint(outPos), outSize);
			Gizmos.color = Color.cyan;
			foreach (Transform item in ((Component)this).transform)
			{
				Transform val = item;
				if (((Component)val).CompareTag("snappoint"))
				{
					Gizmos.DrawSphere(val.position, 0.05f);
				}
			}
		}
	}
	public enum HopperPriority
	{
		ItemDropPull = 0,
		SmelterFuelPush = 10,
		SmelterOrePush = 10,
		ContainerPull = 20,
		ContainerPush = 20,
		HopperPull = 30,
		HopperPush = 30,
		PipePull = 40,
		PipePush = 40,
		BeehivePull = 50,
		TurretPush = 60
	}
	public interface IPullTarget : ITarget, IEqualityComparer<ITarget>
	{
		HopperPriority PullPriority { get; }

		bool IsPickup { get; }

		IEnumerable<ItemData> GetItems();

		void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1);
	}
	public interface IPushTarget : ITarget, IEqualityComparer<ITarget>
	{
		HopperPriority PushPriority { get; }

		bool CanAddItem(ItemData item);

		void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1);
	}
	public interface ITarget : IEqualityComparer<ITarget>
	{
		int NetworkHashCode();

		bool IsValid();

		bool InRange(Vector3 position);
	}
	public class ItemFilter
	{
		private ZNetView zNetView;

		private Inventory inventory;

		private Dictionary<string, ZInt> slots = new Dictionary<string, ZInt>();

		public ItemFilter(ZNetView zNetView, Inventory inventory)
		{
			this.zNetView = zNetView;
			this.inventory = inventory;
		}

		public void Save()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			foreach (ItemData item in inventory.m_inventory)
			{
				Vector2i gridPos = item.m_gridPos;
				int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)item.m_dropPrefab).name);
				SetItemHash(gridPos, stableHashCode);
			}
		}

		public void Clear()
		{
			for (int i = 0; i < inventory.m_width; i++)
			{
				for (int j = 0; j < inventory.m_height; j++)
				{
					SetItemHash(i, j, 0);
				}
			}
		}

		public void Copy(ItemFilter other)
		{
			for (int i = 0; i < inventory.m_width; i++)
			{
				for (int j = 0; j < inventory.m_height; j++)
				{
					SetItemHash(i, j, other.GetItemHash(i, j));
				}
			}
		}

		public void SetItemHash(Vector2i gridPos, int itemHash)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			SetItemHash(gridPos.x, gridPos.y, itemHash);
		}

		public int GetItemHash(Vector2i gridPos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return GetItemHash(gridPos.x, gridPos.y);
		}

		public void SetItemHash(int x, int y, int itemHash)
		{
			GetSlot(x, y).Set(itemHash);
		}

		public int GetItemHash(int x, int y)
		{
			return GetSlot(x, y).Get();
		}

		private ZInt GetSlot(int x, int y)
		{
			string key = $"hopper_filter_{x}_{y}";
			if (slots.TryGetValue(key, out var value))
			{
				return value;
			}
			value = new ZInt(key, 0, zNetView);
			slots[key] = value;
			return value;
		}

		public bool Contains(int itemHash)
		{
			for (int i = 0; i < inventory.m_width; i++)
			{
				for (int j = 0; j < inventory.m_height; j++)
				{
					if (GetItemHash(i, j) == itemHash)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	public class NetworkPiece : MonoBehaviour
	{
		protected ZNetView zNetView;

		protected int OutputCounter;

		public bool IsPushBlocked { get; protected set; }

		public bool IsPullBlocked { get; protected set; }

		protected virtual void Awake()
		{
			zNetView = ((Component)this).GetComponentInParent<ZNetView>();
		}

		public void WakeUp()
		{
			IsPushBlocked = false;
			IsPullBlocked = false;
		}

		public bool IsValid()
		{
			if (Object.op_Implicit((Object)(object)this) && Object.op_Implicit((Object)(object)zNetView) && HopperHelper.IsValidNetView(zNetView))
			{
				return zNetView.HasOwner();
			}
			return false;
		}

		public int NetworkHashCode()
		{
			if (Object.op_Implicit((Object)(object)zNetView) && zNetView.m_zdo != null)
			{
				return HopperHelper.GetNetworkHashCode(zNetView);
			}
			return ((Object)this).GetInstanceID();
		}

		public bool Equals(ITarget x, ITarget y)
		{
			if (x != y)
			{
				return x?.NetworkHashCode() == y?.NetworkHashCode();
			}
			return true;
		}

		public int GetHashCode(ITarget obj)
		{
			return obj.NetworkHashCode();
		}
	}
	public class Pipe : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>, IPullTarget
	{
		[SerializeField]
		private Vector3 outPos = new Vector3(0f, 0f, -1f);

		[SerializeField]
		private Vector3 outSize = new Vector3(0.25f, 0.5f, 0.5f);

		private Container container;

		private ContainerTarget containerTarget;

		private List<IPushTarget> pushTo = new List<IPushTarget>();

		private BoxVisualizer outVisualizer;

		private int lastPullFrame = -1;

		private const float ObjectSearchInterval = 3f;

		private int transferFrame;

		private int objectSearchFrame;

		private int frameOffset;

		public HopperPriority PushPriority { get; } = HopperPriority.PipePull;

		public HopperPriority PullPriority { get; } = HopperPriority.PipePull;

		public bool IsPickup { get; }

		private string DbgId
		{
			get
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				Vector3 position = ((Component)this).transform.position;
				return "Pipe@" + ((Vector3)(ref position)).ToString("F1");
			}
		}

		protected override void Awake()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			base.Awake();
			container = ((Component)this).GetComponent<Container>();
			containerTarget = ((Component)this).GetComponent<ContainerTarget>();
			UpdateTransferRate();
			objectSearchFrame = Mathf.RoundToInt(1f / Time.fixedDeltaTime * 3f);
			frameOffset = Mathf.Abs(((Object)this).GetInstanceID() % transferFrame);
			outVisualizer = ((Component)this).gameObject.AddComponent<BoxVisualizer>();
			outVisualizer.SetData(outPos, outSize, Color.yellow, Plugin.ShowPipeOutputBox);
		}

		private void Start()
		{
			Inventory inventory = container.GetInventory();
			inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(base.WakeUp));
			HopperHelper.OnTargetChanged += OnTargetChanged;
		}

		private void OnDestroy()
		{
			HopperHelper.OnTargetChanged -= OnTargetChanged;
		}

		private void OnTargetChanged(ITarget target)
		{
			if (base.IsPushBlocked && pushTo.Any((IPushTarget t) => t.NetworkHashCode() == target.NetworkHashCode()))
			{
				base.IsPushBlocked = false;
			}
		}

		private void UpdateTransferRate()
		{
			float num = (((Object)this).name.Contains("Iron") ? Plugin.IronTransferRate.Value : Plugin.BronzeTransferRate.Value);
			float num2 = 30f / Mathf.Max(1f, num);
			transferFrame = Mathf.RoundToInt(num2 / Time.fixedDeltaTime);
			if (transferFrame < 1)
			{
				transferFrame = 1;
			}
		}

		private void FixedUpdate()
		{
			if (IsValid() && zNetView.IsOwner() && !Plugin.DisableAllSystems.Value)
			{
				int fixedFrameCount = HopperHelper.GetFixedFrameCount();
				int num = (fixedFrameCount + frameOffset) / transferFrame;
				if ((fixedFrameCount + frameOffset) % transferFrame == 0 && num % 2 == 1 && !base.IsPushBlocked)
				{
					PushItems();
				}
				if ((fixedFrameCount + frameOffset + 1) % objectSearchFrame == 0)
				{
					FindIO();
				}
			}
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		public bool CanAddItem(ItemData item)
		{
			return containerTarget.CanAddItem(item);
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Debug("[" + DbgId + "] AddItem '" + (item?.m_shared?.m_name ?? "null") + "' pushed by upstream");
			containerTarget.AddItem(item, source, sender, amount);
		}

		public IEnumerable<ItemData> GetItems()
		{
			if (HopperHelper.GetFixedFrameCount() == lastPullFrame)
			{
				return Enumerable.Empty<ItemData>();
			}
			return containerTarget.GetItems();
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Debug("[" + DbgId + "] RemoveItem '" + (item?.m_shared?.m_name ?? "null") + "' pulled by hopper");
			lastPullFrame = HopperHelper.GetFixedFrameCount();
			containerTarget.RemoveItem(item, destination, destinationPos, sender, amount);
		}

		private void PushItems()
		{
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			if (pushTo.Count == 0 || container.GetInventory().NrOfItems() == 0)
			{
				base.IsPushBlocked = true;
				return;
			}
			int num = OutputCounter % pushTo.Count;
			IPushTarget to = pushTo[num];
			OutputCounter++;
			if (!to.IsValid())
			{
				Plugin.Debug($"[{DbgId}] Push target [{num}] invalid, skipping");
				return;
			}
			ItemData val = container.GetInventory().FindLastItem((ItemData i) => to.CanAddItem(i));
			if (val != null)
			{
				Plugin.Debug(string.Format("[{0}] Pushing '{1}' -> target [{2}] ({3}) (counter={4})", DbgId, val.m_shared?.m_name ?? "null", num, to.GetType().Name, OutputCounter));
				to.AddItem(val, container.GetInventory(), zNetView.m_zdo.m_uid);
				HopperHelper.NotifyChange(this);
				HopperHelper.NotifyChange(to);
			}
			else
			{
				Plugin.Debug($"[{DbgId}] No pushable item for target [{num}] ({to.GetType().Name}) (full or filtered)");
				base.IsPushBlocked = true;
			}
		}

		private void FindIO()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			Quaternion rotation = ((Component)this).transform.rotation;
			List<IPushTarget> list = HopperHelper.FindTargets(((Component)this).transform.TransformPoint(outPos), outSize, rotation, (IPushTarget i) => i.PushPriority, this);
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, 2.5f, LayerMask.GetMask(new string[2] { "piece", "piece_nonsolid" }));
			foreach (Collider val in array)
			{
				Hopper hopper = ((Component)val).GetComponentInParent<Hopper>();
				if ((Object)(object)hopper != (Object)null && !list.Any((IPushTarget t) => t.NetworkHashCode() == hopper.NetworkHashCode()))
				{
					list.Add(hopper);
				}
			}
			List<IPushTarget> list2 = new List<IPushTarget>();
			Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren<Collider>();
			foreach (IPushTarget item in list)
			{
				if (item is Hopper hopper2)
				{
					if (HopperHelper.BoxIntersectsColliders(((Component)hopper2).transform.TransformPoint(hopper2.InPos), hopper2.InSize, ((Component)hopper2).transform.rotation, componentsInChildren))
					{
						list2.Add(item);
						Plugin.Debug("[" + DbgId + "] Added Hopper output via body-overlap: " + ((Object)((Component)hopper2).gameObject).name);
					}
					else
					{
						Plugin.Debug("[" + DbgId + "] Skipped Hopper (no body-overlap): " + ((Object)((Component)hopper2).gameObject).name);
					}
					continue;
				}
				list2.Add(item);
				MonoBehaviour val2 = (MonoBehaviour)((item is MonoBehaviour) ? item : null);
				if (val2 != null)
				{
					Plugin.Debug("[" + DbgId + "] Added standard output target: " + ((Object)((Component)val2).gameObject).name);
				}
			}
			pushTo = list2;
			Plugin.Debug("[" + DbgId + "] Output list: [" + string.Join(", ", pushTo.Select((IPushTarget t) => t.GetType().Name)) + "]");
			WakeUp();
		}

		private void OnDrawGizmos()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Gizmos.color = Color.yellow;
			Gizmos.DrawWireCube(((Component)this).transform.TransformPoint(outPos), outSize);
			Gizmos.color = Color.cyan;
			foreach (Transform item in ((Component)this).transform)
			{
				Transform val = item;
				if (((Component)val).CompareTag("snappoint"))
				{
					Gizmos.DrawSphere(val.position, 0.05f);
				}
			}
		}
	}
	public class BeehiveTarget : NetworkPiece, IPullTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Beehive beehive;

		private const string RequestOwnershipRPC = "VH_RequestOwnership";

		public HopperPriority PullPriority { get; } = HopperPriority.BeehivePull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			beehive = ((Component)this).GetComponent<Beehive>();
			beehive.m_nview.Register("VH_RequestOwnership", (Action<long>)RPC_RequestOwnership);
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		public IEnumerable<ItemData> GetItems()
		{
			if (Object.op_Implicit((Object)(object)beehive.m_honeyItem) && beehive.GetHoneyLevel() > 0)
			{
				ItemHelper.CheckDropPrefab(beehive.m_honeyItem);
				yield return beehive.m_honeyItem.m_itemData;
			}
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			if (!beehive.m_nview.IsOwner())
			{
				beehive.m_nview.InvokeRPC("VH_RequestOwnership", Array.Empty<object>());
				return;
			}
			int honeyLevel = beehive.GetHoneyLevel();
			int num = Mathf.Min(honeyLevel, amount);
			if (num > 0)
			{
				beehive.m_nview.GetZDO().Set(ZDOVars.s_level, honeyLevel - num, false);
				destination.AddItem(item.Clone(), num, destinationPos.x, destinationPos.y, false);
			}
		}

		private void RPC_RequestOwnership(long sender)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (beehive.m_nview.IsOwner())
			{
				beehive.m_nview.GetZDO().SetOwner(sender);
				ZDOMan.instance.ForceSendZDO(sender, beehive.m_nview.GetZDO().m_uid);
			}
		}
	}
	public class ClayCollectorTarget : NetworkPiece, IPullTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Component collectorComponent;

		private MethodInfo getTarLevelMethod;

		private MethodInfo resetLevelMethod;

		private FieldInfo clayItemField;

		private const string RequestOwnershipRPC = "VH_RequestOwnership_Clay";

		public HopperPriority PullPriority { get; } = HopperPriority.BeehivePull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			collectorComponent = ((Component)this).GetComponent("ClayCollector");
			if ((Object)(object)collectorComponent != (Object)null)
			{
				Type type = ((object)collectorComponent).GetType();
				getTarLevelMethod = type.GetMethod("GetTarLevel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				resetLevelMethod = type.GetMethod("ResetLevel", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				clayItemField = type.GetField("m_clayItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				Plugin.Debug($"[ClayCollector] Found component. Methods: GetTarLevel={getTarLevelMethod != null}, ResetLevel={resetLevelMethod != null}, m_clayItem={clayItemField != null}");
			}
			else
			{
				Plugin.Debug("[ClayCollector] Critical: 'ClayCollector' component not found on this object!");
			}
			if ((Object)(object)zNetView != (Object)null)
			{
				zNetView.Register("VH_RequestOwnership_Clay", (Action<long>)RPC_RequestOwnership);
			}
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		public IEnumerable<ItemData> GetItems()
		{
			if ((Object)(object)zNetView == (Object)null || !zNetView.IsValid() || (Object)(object)collectorComponent == (Object)null || GetCurrentLevel() <= 0)
			{
				yield break;
			}
			GameObject clayPrefab = GetClayPrefab();
			if (Object.op_Implicit((Object)(object)clayPrefab))
			{
				ItemDrop component = clayPrefab.GetComponent<ItemDrop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					yield return component.m_itemData;
				}
			}
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)zNetView == (Object)null || !zNetView.IsValid() || (Object)(object)collectorComponent == (Object)null)
			{
				return;
			}
			if (!zNetView.IsOwner())
			{
				zNetView.InvokeRPC("VH_RequestOwnership_Clay", Array.Empty<object>());
				return;
			}
			int currentLevel = GetCurrentLevel();
			if (currentLevel > 0)
			{
				if (resetLevelMethod != null)
				{
					resetLevelMethod.Invoke(collectorComponent, null);
				}
				else
				{
					zNetView.GetZDO().Set("Produced", 0);
					zNetView.GetZDO().Set("level", 0);
				}
				destination.AddItem(item.Clone(), currentLevel, destinationPos.x, destinationPos.y, false);
			}
		}

		private int GetCurrentLevel()
		{
			if (getTarLevelMethod != null)
			{
				return (int)getTarLevelMethod.Invoke(collectorComponent, null);
			}
			int num = zNetView.GetZDO().GetInt("Produced", 0);
			if (num == 0)
			{
				num = zNetView.GetZDO().GetInt("level", 0);
			}
			return num;
		}

		private GameObject GetClayPrefab()
		{
			if (clayItemField != null)
			{
				object? value = clayItemField.GetValue(collectorComponent);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("BFP_Clay");
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				itemPrefab = ObjectDB.instance.GetItemPrefab("Clay");
			}
			return itemPrefab;
		}

		private void RPC_RequestOwnership(long sender)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)zNetView == (Object)null) && zNetView.IsOwner())
			{
				zNetView.GetZDO().SetOwner(sender);
				ZDOMan.instance.ForceSendZDO(sender, zNetView.GetZDO().m_uid);
			}
		}
	}
	public class ContainerTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>, IPullTarget
	{
		private Container container;

		public HopperPriority PushPriority { get; } = HopperPriority.ContainerPull;

		public HopperPriority PullPriority { get; } = HopperPriority.ContainerPull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			container = ((Component)this).GetComponent<Container>();
		}

		private void Start()
		{
			if ((Object)(object)container != (Object)null && container.GetInventory() != null)
			{
				Inventory inventory = container.GetInventory();
				inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(OnInventoryChanged));
			}
		}

		private void OnInventoryChanged()
		{
			HopperHelper.NotifyChange(this);
		}

		public IEnumerable<ItemData> GetItems()
		{
			return container.GetInventory().GetItemInReverseOrder();
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			ContainerHandler.AddItemToChest(container, item, source, new Vector2i(-1, -1), sender, amount);
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			ContainerHandler.RemoveItemFromChest(container, item, destination, destinationPos, sender, amount, (ItemData)null);
		}

		public bool CanAddItem(ItemData item)
		{
			return container.GetInventory().CanAddItem(item, 1);
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}
	}
	public class CookingStationTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>, IPullTarget
	{
		private CookingStation cookingStation;

		private static FieldInfo cookableField;

		private static bool fieldDetected;

		public HopperPriority PushPriority { get; } = HopperPriority.SmelterFuelPush;

		public HopperPriority PullPriority { get; } = HopperPriority.HopperPull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			cookingStation = ((Component)this).GetComponent<CookingStation>();
			FieldInfo[] fields = typeof(CookingStation).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				Plugin.Debug($"CookingStation field: {fieldInfo.FieldType} {fieldInfo.Name}");
			}
			if (!fieldDetected)
			{
				cookableField = typeof(CookingStation).GetField("m_cookable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (cookableField == null)
				{
					cookableField = typeof(CookingStation).GetField("m_conversion", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				Plugin.Debug("Checking " + ((object)this).GetType().Name);
				Plugin.Debug("cookableField resolved to: " + (cookableField?.Name ?? "NULL"));
				fieldDetected = true;
			}
		}

		private void Start()
		{
			string[] array = new string[11]
			{
				"RPC_AddFuel", "RPC_AddItem", "RPC_RemoveDoneItem", "RPC_SetSlotVisual", "RPC_RequestOwn", "RPC_Pick", "RPC_RemoveItem", "RPC_ClearSlot", "RPC_SetCookingStation", "RPC_AddItemToSlot",
				"RPC_RemoveSlot"
			};
			foreach (string text in array)
			{
				int stableHashCode = StringExtensionMethods.GetStableHashCode(text);
				if (cookingStation.m_nview.m_functions.ContainsKey(stableHashCode))
				{
					Plugin.Debug($"MATCHED: '{text}' = {stableHashCode}");
				}
			}
			foreach (int key in cookingStation.m_nview.m_functions.Keys)
			{
				Plugin.Debug($"Registered hash: {key}");
			}
		}

		private bool IsFuelItem(ItemData item)
		{
			if ((Object)(object)cookingStation.m_fuelItem == (Object)null)
			{
				return false;
			}
			return cookingStation.m_fuelItem.m_itemData.m_shared.m_name == item.m_shared.m_name;
		}

		private bool IsCookableItem(ItemData item)
		{
			if (cookableField == null)
			{
				Plugin.Debug("cookableField is null — reflection failed at Awake");
				return false;
			}
			if (!(cookableField.GetValue(cookingStation) is IEnumerable enumerable))
			{
				Plugin.Debug("cookableList cast failed on field: " + cookableField.Name);
				return false;
			}
			foreach (object item2 in enumerable)
			{
				FieldInfo field = item2.GetType().GetField("m_from", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					continue;
				}
				object? value = field.GetValue(item2);
				ItemDrop val = (ItemDrop)((value is ItemDrop) ? value : null);
				if (!((Object)(object)val == (Object)null))
				{
					Plugin.Debug("Comparing incoming '" + item.m_shared.m_name + "' vs conversion '" + val.m_itemData.m_shared.m_name + "'");
					if (val.m_itemData.m_shared.m_name == item.m_shared.m_name)
					{
						return true;
					}
				}
			}
			return false;
		}

		private bool IsIncompatibleItem(ItemData item)
		{
			FieldInfo field = typeof(CookingStation).GetField("m_incompatibleItems", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return false;
			}
			if (!(field.GetValue(cookingStation) is IEnumerable enumerable))
			{
				return false;
			}
			foreach (object item2 in enumerable)
			{
				FieldInfo field2 = item2.GetType().GetField("m_item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (!(field2 == null))
				{
					object? value = field2.GetValue(item2);
					ItemDrop val = (ItemDrop)((value is ItemDrop) ? value : null);
					if ((Object)(object)val != (Object)null && val.m_itemData.m_shared.m_name == item.m_shared.m_name)
					{
						return true;
					}
				}
			}
			return false;
		}

		private bool CanAddFuel()
		{
			if ((Object)(object)cookingStation.m_fuelItem == (Object)null)
			{
				return false;
			}
			return cookingStation.GetFuel() < (float)cookingStation.m_maxFuel;
		}

		public bool CanAddItem(ItemData item)
		{
			if (IsIncompatibleItem(item))
			{
				return false;
			}
			if ((Object)(object)cookingStation == (Object)null)
			{
				Plugin.Debug(((object)this).GetType().Name + " cookingStation is null");
				return false;
			}
			if (IsFuelItem(item))
			{
				Plugin.Debug(((object)this).GetType().Name + "'s " + item.m_shared.m_name + " is fuel");
				return CanAddFuel();
			}
			if (cookableField != null)
			{
				if (IsCookableItem(item))
				{
					Plugin.Debug(((object)this).GetType().Name + "'s " + item.m_shared.m_name + " is cookable");
					return cookingStation.GetFreeSlot() != -1;
				}
				Plugin.Debug(((object)this).GetType().Name + "'s " + item.m_shared.m_name + " is unknown");
				return false;
			}
			Plugin.Debug("cookableField null, falling back to slot check for '" + item.m_shared.m_name + "'");
			return cookingStation.GetFreeSlot() != -1;
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			if (source.RemoveItem(item, amount))
			{
				if (IsFuelItem(item))
				{
					cookingStation.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
					return;
				}
				cookingStation.m_nview.InvokeRPC("RPC_AddItem", new object[2]
				{
					((Object)item.m_dropPrefab).name,
					item.m_cheated
				});
			}
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		public IEnumerable<ItemData> GetItems()
		{
			List<ItemData> list = new List<ItemData>();
			if ((Object)(object)cookingStation == (Object)null)
			{
				return list;
			}
			int num = cookingStation.m_slots.Length;
			for (int i = 0; i < num; i++)
			{
				string text = cookingStation.m_nview.GetZDO().GetString($"slot{i}", "");
				if (string.IsNullOrEmpty(text) || text == "0")
				{
					continue;
				}
				bool num2 = GetConversionForCooked(text) != null;
				ItemDrop overCookedItem = cookingStation.m_overCookedItem;
				bool flag = text == ((overCookedItem != null) ? ((Object)overCookedItem).name : null);
				if (!num2 && !flag)
				{
					continue;
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(text);
				if (!((Object)(object)prefab == (Object)null))
				{
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null))
					{
						list.Add(component.m_itemData.Clone());
					}
				}
			}
			return list;
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			int num = cookingStation.m_slots.Length;
			ZDO zDO = cookingStation.m_nview.GetZDO();
			for (int i = 0; i < num; i++)
			{
				string text = zDO.GetString($"slot{i}", "");
				GameObject prefab = ZNetScene.instance.GetPrefab(text);
				if (!((Object)(object)prefab == (Object)null))
				{
					ItemDrop component = prefab.GetComponent<ItemDrop>();
					if (!((Object)(object)component == (Object)null) && !(component.m_itemData.m_shared.m_name != item.m_shared.m_name))
					{
						cookingStation.m_nview.ClaimOwnership();
						zDO.Set($"slot{i}", "");
						zDO.Set($"slot{i}_ct", 0f);
						cookingStation.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetSlotVisual", new object[2] { i, "" });
						destination.AddItem(item.Clone(), 1, destinationPos.x, destinationPos.y, false);
						Plugin.Debug($"RemoveItem: cleared slot {i} ({text}) via ZDO write");
						return;
					}
				}
			}
			Plugin.Debug("RemoveItem: no slot found for '" + item.m_shared.m_name + "'");
		}

		private ItemConversion GetConversionForCooked(string cookedItemName)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Expected O, but got Unknown
			if (cookableField == null)
			{
				return null;
			}
			if (!(cookableField.GetValue(cookingStation) is IEnumerable enumerable))
			{
				return null;
			}
			foreach (ItemConversion item in enumerable)
			{
				ItemConversion val = item;
				ItemDrop to = val.m_to;
				if (((to != null) ? ((Object)to).name : null) == cookedItemName)
				{
					return val;
				}
			}
			return null;
		}
	}
	public class FermenterTarget : NetworkPiece, IPullTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Fermenter fermenter;

		private const string RequestOwnershipRPC = "VH_RequestOwnership";

		public HopperPriority PullPriority { get; } = HopperPriority.BeehivePull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			fermenter = ((Component)this).GetComponent<Fermenter>();
			fermenter.m_nview.Register("VH_RequestOwnership", (Action<long>)RPC_RequestOwnership);
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}

		public IEnumerable<ItemData> GetItems()
		{
			if ((int)fermenter.GetStatus() != 3)
			{
				yield break;
			}
			string text = fermenter.m_nview.GetZDO().GetString("item", "");
			if (string.IsNullOrEmpty(text))
			{
				yield break;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text);
			if (Object.op_Implicit((Object)(object)itemPrefab))
			{
				ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
				if (Object.op_Implicit((Object)(object)component))
				{
					yield return component.m_itemData;
				}
			}
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if (!fermenter.m_nview.IsOwner())
			{
				fermenter.m_nview.InvokeRPC("VH_RequestOwnership", Array.Empty<object>());
			}
			else if ((int)fermenter.GetStatus() == 3)
			{
				fermenter.m_nview.GetZDO().Set("status", 0);
				fermenter.m_nview.GetZDO().Set("item", "");
				fermenter.m_nview.GetZDO().Set("startTime", 0L);
				int num = ((!item.m_shared.m_name.Contains("mead")) ? 1 : 6);
				destination.AddItem(item.Clone(), num, destinationPos.x, destinationPos.y, false);
			}
		}

		private void RPC_RequestOwnership(long sender)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (fermenter.m_nview.IsOwner())
			{
				fermenter.m_nview.GetZDO().SetOwner(sender);
				ZDOMan.instance.ForceSendZDO(sender, fermenter.m_nview.GetZDO().m_uid);
			}
		}
	}
	public class FireplaceFuelTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Fireplace fireplace;

		public HopperPriority PushPriority { get; } = HopperPriority.SmelterFuelPush;

		protected override void Awake()
		{
			base.Awake();
			fireplace = ((Component)this).GetComponent<Fireplace>();
		}

		public bool CanAddItem(ItemData item)
		{
			bool num = Object.op_Implicit((Object)(object)fireplace.m_fuelItem) && fireplace.m_fuelItem.m_itemData.m_shared.m_name == item.m_shared.m_name;
			float num2 = fireplace.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
			if (num)
			{
				return num2 < fireplace.m_maxFuel - 1f;
			}
			return false;
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			float num = fireplace.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f);
			int num2 = Mathf.FloorToInt(fireplace.m_maxFuel - num);
			int num3 = Mathf.Min(amount, num2);
			if (num3 > 0 && source.RemoveItem(item, num3))
			{
				for (int i = 0; i < num3; i++)
				{
					fireplace.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
			}
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}
	}
	public class ItemDropTarget : NetworkPiece, IPullTarget, ITarget, IEqualityComparer<ITarget>
	{
		private ItemDrop itemDrop;

		public HopperPriority PullPriority { get; }

		public bool IsPickup { get; } = true;

		protected override void Awake()
		{
			base.Awake();
			itemDrop = ((Component)this).GetComponent<ItemDrop>();
		}

		public IEnumerable<ItemData> GetItems()
		{
			if (Object.op_Implicit((Object)(object)itemDrop))
			{
				ItemHelper.CheckDropPrefab(itemDrop);
				yield return itemDrop.m_itemData;
			}
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			if (!itemDrop.m_nview.IsOwner())
			{
				itemDrop.RequestOwn();
				return;
			}
			int stack = itemDrop.m_itemData.m_stack;
			int num = Mathf.Min(stack, amount);
			if (num > 0)
			{
				if (num >= stack)
				{
					itemDrop.m_nview.Destroy();
				}
				else
				{
					ItemData itemData = itemDrop.m_itemData;
					itemData.m_stack -= num;
					itemDrop.m_nview.GetZDO().Set(ZDOVars.s_stack, itemDrop.m_itemData.m_stack, false);
				}
				destination.AddItem(item.Clone(), num, destinationPos.x, destinationPos.y, false);
			}
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}
	}
	public class SmelterFuelTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Smelter smelter;

		public HopperPriority PushPriority { get; } = HopperPriority.SmelterFuelPush;

		protected override void Awake()
		{
			base.Awake();
			smelter = ((Component)this).GetComponent<Smelter>();
		}

		public bool CanAddItem(ItemData item)
		{
			if (Object.op_Implicit((Object)(object)smelter.m_fuelItem) && smelter.m_fuelItem.m_itemData.m_shared.m_name == item.m_shared.m_name)
			{
				return smelter.GetFuel() < (float)(smelter.m_maxFuel - 1);
			}
			return false;
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			float fuel = smelter.GetFuel();
			int num = Mathf.FloorToInt((float)smelter.m_maxFuel - fuel);
			int num2 = Mathf.Min(amount, num);
			if (num2 > 0 && source.RemoveItem(item, num2))
			{
				for (int i = 0; i < num2; i++)
				{
					smelter.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
			}
		}

		public bool InRange(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return HopperHelper.IsInRange(position, ((Component)smelter.m_addWoodSwitch).transform.position, 1f);
		}
	}
	public class SmelterOreTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Smelter smelter;

		public HopperPriority PushPriority { get; } = HopperPriority.SmelterFuelPush;

		protected override void Awake()
		{
			base.Awake();
			smelter = ((Component)this).GetComponent<Smelter>();
		}

		public bool CanAddItem(ItemData item)
		{
			if (smelter.IsItemAllowed(item))
			{
				return smelter.GetQueueSize() < smelter.m_maxOre;
			}
			return false;
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			int queueSize = smelter.GetQueueSize();
			int num = smelter.m_maxOre - queueSize;
			int num2 = Mathf.Min(amount, num);
			if (num2 <= 0)
			{
				return;
			}
			string name = ((Object)item.m_dropPrefab).name;
			bool cheated = item.m_cheated;
			if (!source.RemoveItem(item, num2))
			{
				Plugin.Debug($"SmelterOreTarget: failed to remove {num2}x '{item.m_shared.m_name}'");
				return;
			}
			for (int i = 0; i < num2; i++)
			{
				smelter.m_nview.InvokeRPC("RPC_AddOre", new object[2] { name, cheated });
			}
		}

		public bool InRange(Vector3 position)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return HopperHelper.IsInRange(position, ((Component)smelter.m_addOreSwitch).transform.position, 1f);
		}
	}
	public class TurretTarget : NetworkPiece, IPushTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Turret turret;

		public HopperPriority PushPriority { get; } = HopperPriority.TurretPush;

		protected override void Awake()
		{
			base.Awake();
			turret = ((Component)this).GetComponent<Turret>();
		}

		public void AddItem(ItemData item, Inventory source, ZDOID sender, int amount = 1)
		{
			int ammo = turret.GetAmmo();
			int num = turret.m_maxAmmo - ammo;
			int num2 = Mathf.Min(amount, num);
			if (num2 > 0 && source.RemoveItem(item, num2))
			{
				for (int i = 0; i < num2; i++)
				{
					turret.m_nview.InvokeRPC("RPC_AddAmmo", new object[1] { ((Object)item.m_dropPrefab).name });
				}
			}
		}

		public bool CanAddItem(ItemData item)
		{
			if (!turret.IsItemAllowed(((Object)item.m_dropPrefab).name))
			{
				return false;
			}
			if (turret.GetAmmo() > 0 && turret.GetAmmoType() != ((Object)item.m_dropPrefab).name)
			{
				return false;
			}
			if (turret.GetAmmo() >= turret.m_maxAmmo)
			{
				return false;
			}
			return true;
		}

		public bool InRange(Vector3 position)
		{
			return true;
		}
	}
	public class WindmillTarget : NetworkPiece, IPullTarget, ITarget, IEqualityComparer<ITarget>
	{
		private Smelter smelter;

		public HopperPriority PullPriority { get; } = HopperPriority.HopperPull;

		public bool IsPickup { get; }

		protected override void Awake()
		{
			base.Awake();
			smelter = ((Component)this).GetComponent<Smelter>();
			FieldInfo[] fields = typeof(Smelter).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				Plugin.Debug($"Smelter field: {fieldInfo.FieldType} {fieldInfo.Name}");
			}
		}

		private void Start()
		{
			ZDO zDO = smelter.m_nview.GetZDO();
			Plugin.Debug(string.Format("Windmill ZDO - SpawnAmount: {0}", zDO.GetInt("SpawnAmount", -999)));
			Plugin.Debug(string.Format("Windmill ZDO - queued: {0}", zDO.GetInt("queued", -999)));
			Plugin.Debug(string.Format("Windmill ZDO - items: {0}", zDO.GetInt("items", -999)));
			Plugin.Debug("Windmill ZDO - SpawnOre: " + zDO.GetString("SpawnOre", "NULL"));
		}

		public bool InRange(Vector3 position)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)smelter) || !Object.op_Implicit((Object)(object)smelter.m_emptyOreSwitch))
			{
				return false;
			}
			return HopperHelper.IsInRange(position, ((Component)smelter.m_emptyOreSwitch).transform.position, 1.5f);
		}

		public IEnumerable<ItemData> GetItems()
		{
			List<ItemData> list = new List<ItemData>();
			if (!Object.op_Implicit((Object)(object)smelter))
			{
				return list;
			}
			int num = smelter.m_nview.GetZDO().GetInt("SpawnAmount", 0);
			if (num <= 0)
			{
				return list;
			}
			ItemConversion val = ((smelter.m_conversion.Count > 0) ? smelter.m_conversion[0] : null);
			if ((Object)(object)val?.m_to == (Object)null)
			{
				return list;
			}
			for (int i = 0; i < num; i++)
			{
				list.Add(val.m_to.m_itemData.Clone());
			}
			return list;
		}

		public void RemoveItem(ItemData item, Inventory destination, Vector2i destinationPos, ZDOID sender, int amount = 1)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = smelter.m_nview.GetZDO();
			int num = zDO.GetInt("SpawnAmount", 0);
			int num2 = Mathf.Min(num, amount);
			if (num2 > 0)
			{
				smelter.m_nview.ClaimOwnership();
				zDO.Set("SpawnAmount", num - num2);
				destination.AddItem(item.Clone(), num2, destinationPos.x, destinationPos.y, false);
				Plugin.Debug($"RemoveItem: removed {num2} {item.m_shared.m_name} from Windmill via ZDO write");
			}
		}
	}
	public abstract class ZProperty<T>
	{
		public string Key { get; }

		public T DefaultValue { get; }

		protected ZNetView NetView { get; }

		protected int KeyHash { get; }

		private string RPCName { get; }

		protected ZProperty(string key, T defaultValue, ZNetView netView)
		{
			Key = key;
			RPCName = "RPC_" + key;
			KeyHash = StringExtensionMethods.GetStableHashCode(Key);
			DefaultValue = defaultValue;
			NetView = netView;
			NetView.Register<T>(RPCName, (Action<long, T>)RPCSet);
		}

		public void Set(T value)
		{
			if (NetView.IsValid() && NetView.IsOwner())
			{
				SetValue(value);
				return;
			}
			NetView.InvokeRPC(RPCName, new object[1] { value });
		}

		public void Reset()
		{
			Set(DefaultValue);
		}

		public abstract T Get();

		protected abstract void SetValue(T value);

		private void RPCSet(long sender, T value)
		{
			SetValue(value);
		}
	}
	public class ZBool : ZProperty<bool>
	{
		public ZBool(string key, bool defaultValue, ZNetView zNetView)
			: base(key, defaultValue, zNetView)
		{
		}

		public override bool Get()
		{
			if ((Object)(object)base.NetView == (Object)null || !base.NetView.IsValid())
			{
				return base.DefaultValue;
			}
			ZDO zDO = base.NetView.GetZDO();
			if (zDO == null)
			{
				return base.DefaultValue;
			}
			return zDO.GetBool(base.KeyHash, base.DefaultValue);
		}

		protected override void SetValue(bool value)
		{
			if (!((Object)(object)base.NetView == (Object)null) && base.NetView.IsValid())
			{
				ZDO zDO = base.NetView.GetZDO();
				if (zDO != null)
				{
					zDO.Set(base.KeyHash, value);
				}
			}
		}
	}
	public class ZInt : ZProperty<int>
	{
		public ZInt(string key, int defaultValue, ZNetView zNetView)
			: base(key, defaultValue, zNetView)
		{
		}

		public override int Get()
		{
			if ((Object)(object)base.NetView == (Object)null || !base.NetView.IsValid())
			{
				return base.DefaultValue;
			}
			ZDO zDO = base.NetView.GetZDO();
			if (zDO == null)
			{
				return base.DefaultValue;
			}
			return zDO.GetInt(base.KeyHash, base.DefaultValue);
		}

		protected override void SetValue(int value)
		{
			if (!((Object)(object)base.NetView == (Object)null) && base.NetView.IsValid())
			{
				ZDO zDO = base.NetView.GetZDO();
				if (zDO != null)
				{
					zDO.Set(base.KeyHash, value, false);
				}
			}
		}
	}
}
namespace ValheimHopper.Logic.Helper
{
	public class BoxVisualizer : MonoBehaviour
	{
		private LineRenderer lineRenderer;

		private Vector3 boxCenter;

		private Vector3 boxSize;

		private ConfigEntry<bool> config;

		public void SetData(Vector3 center, Vector3 size, Color color, ConfigEntry<bool> configEntry)
		{
			//IL_0001: 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_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			boxCenter = center;
			boxSize = size;
			config = configEntry;
			if ((Object)(object)lineRenderer == (Object)null)
			{
				GameObject val = new GameObject("BoxVisualizerLine");
				val.transform.SetParent(((Component)this).transform, false);
				lineRenderer = val.AddComponent<LineRenderer>();
				lineRenderer.startWidth = 0.02f;
				lineRenderer.endWidth = 0.02f;
				lineRenderer.useWorldSpace = false;
				Shader val2 = Shader.Find("Sprites/Default");
				if ((Object)(object)val2 == (Object)null)
				{
					val2 = Shader.Find("Standard");
				}
				if ((Object)(object)val2 != (Object)null)
				{
					((Renderer)lineRenderer).material = new Material(val2);
				}
				lineRenderer.positionCount = 16;
			}
			lineRenderer.startColor = color;
			lineRenderer.endColor = color;
			UpdateVisual();
		}

		private void Update()
		{
			if (config != null && (Object)(object)lineRenderer != (Object)null)
			{
				bool value = config.Value;
				if (((Component)lineRenderer).gameObject.activeSelf != value)
				{
					((Component)lineRenderer).gameObject.SetActive(value);
				}
			}
		}

		private void UpdateVisual()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)lineRenderer == (Object)null))
			{
				Vector3 val = boxSize / 2f;
				Vector3 val2 = boxCenter;
				Vector3 val3 = val2 + new Vector3(0f - val.x, 0f - val.y, 0f - val.z);
				Vector3 val4 = val2 + new Vector3(val.x, 0f - val.y, 0f - val.z);
				Vector3 val5 = val2 + new Vector3(val.x, val.y, 0f - val.z);
				Vector3 val6 = val2 + new Vector3(0f - val.x, val.y, 0f - val.z);
				Vector3 val7 = val2 + new Vector3(0f - val.x, 0f - val.y, val.z);
				Vector3 val8 = val2 + new Vector3(val.x, 0f - val.y, val.z);
				Vector3 val9 = val2 + new Vector3(val.x, val.y, val.z);
				Vector3 val10 = val2 + new Vector3(0f - val.x, val.y, val.z);
				lineRenderer.SetPosition(0, val3);
				lineRenderer.SetPosition(1, val4);
				lineRenderer.SetPosition(2, val5);
				lineRenderer.SetPosition(3, val6);
				lineRenderer.SetPosition(4, val3);
				lineRenderer.SetPosition(5, val7);
				lineRenderer.SetPosition(6, val8);
				lineRenderer.SetPosition(7, val4);
				lineRenderer.SetPosition(8, val8);
				lineRenderer.SetPosition(9, val9);
				lineRenderer.SetPosition(10, val5);
				lineRenderer.SetPosition(11, val9);
				lineRenderer.SetPosition(12, val10);
				lineRenderer.SetPosition(13, val6);
				lineRenderer.SetPosition(14, val10);
				lineRenderer.SetPosition(15, val7);
			}
		}
	}
	public static class HopperHelper
	{
		private static readonly Collider[] tempColliders = (Collider[])(object)new Collider[256];

		private static int PieceMask { get; } = LayerMask.GetMask(new string[6] { "piece", "piece_nonsolid", "Default", "static_solid", "viewblock", "vehicle" });

		private static int ItemMask { get; } = LayerMask.GetMask(new string[1] { "item" });

		public static event Action<ITarget> OnTargetChanged;

		public static void NotifyChange(ITarget target)
		{
			HopperHelper.OnTargetChanged?.Invoke(target);
		}

		public static bool IsInRange(Vector3 position, Vector3 target, float range)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: 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)
			return Vector3.SqrMagnitude(target - position) < range * range;
		}

		public static bool IsInRange(Vector3 position, Collider collider, float range)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Bounds bounds = collider.bounds;
			((Bounds)(ref bounds)).Expand(range);
			return ((Bounds)(ref bounds)).Contains(position);
		}

		public static bool IsValidNetView(ZNetView netView)
		{
			if (Object.op_Implicit((Object)(object)netView) && netView.IsValid())
			{
				return netView.m_zdo != null;
			}
			return false;
		}

		public static int GetNetworkHashCode(ZNetView netView)
		{
			return ((object)Unsafe.As<ZDOID, ZDOID>(ref netView.m_zdo.m_uid)/*cast due to .constrained prefix*/).GetHashCode();
		}

		public static int GetFixedFrameCount()
		{
			return Mathf.RoundToInt(Time.fixedTime / Time.fixedDeltaTime);
		}

		public static List<T> FindTargets<T>(Vector3 pos, Vector3 size, Quaternion rotation, Func<T, HopperPriority> orderBy, ITarget exclude) where T : ITarget
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			List<T> list = new List<T>();
			int num = Physics.OverlapBoxNonAlloc(pos, size / 2f, tempColliders, rotation, PieceMask | ItemMask);
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < num; i++)
			{
				GameObject gameObject = ((Component)tempColliders[i]).gameObject;
				int instanceID = ((Object)gameObject).GetInstanceID();
				if (hashSet.Contains(instanceID))
				{
					continue;
				}
				hashSet.Add(instanceID);
				T[] componentsInParent = gameObject.GetComponentsInParent<T>();
				for (int j = 0; j < componentsInParent.Length; j++)
				{
					T item = componentsInParent[j];
					if (item.InRange(pos) && item.IsValid() && item.NetworkHashCode() != exclude.NetworkHashCode())
					{
						list.Add(item);
					}
				}
			}
			if (list.Count == 0 && num > 0)
			{
				for (int k = 0; k < num; k++)
				{
					Plugin.Debug("[" + exclude.GetType().Name + "] Physical hit: " + ((Object)((Component)tempColliders[k]).gameObject).name + " (Layer: " + LayerMask.LayerToName(((Component)tempColliders[k]).gameObject.layer) + ")");
				}
			}
			return (from t in list.OrderByDescending(orderBy)
				group t by t.NetworkHashCode() into t
				select t.First()).ToList();
		}

		public static bool BoxIntersectsColliders(Vector3 boxPos, Vector3 boxSize, Quaternion boxRot, Collider[] targetColliders)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			int num = 3;
			Vector3 val = default(Vector3);
			for (int i = 0; i < num; i++)
			{
				for (int j = 0; j < num; j++)
				{
					for (int k = 0; k < num; k++)
					{
						float num2 = ((float)i + 0.5f) / (float)num - 0.5f;
						float num3 = ((float)j + 0.5f) / (float)num - 0.5f;
						float num4 = ((float)k + 0.5f) / (float)num - 0.5f;
						((Vector3)(ref val))..ctor(num2 * boxSize.x, num3 * boxSize.y, num4 * boxSize.z);
						if (IsPointInAnyCollider(boxPos + boxRot * val, targetColliders))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		private static bool IsPointInAnyCollider(Vector3 point, Collider[] colliders)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			foreach (Collider collider in colliders)
			{
				if (IsPointInCollider(point, collider))
				{
					return true;
				}
			}
			return false;
		}

		private static bool IsPointInCollider(Vector3 point, Collider collider)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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)
			BoxCollider val = (BoxCollider)(object)((collider is BoxCollider) ? collider : null);
			if (val != null)
			{
				Vector3 val2 = ((Component)val).transform.InverseTransformPoint(point) - val.center;
				if (Mathf.Abs(val2.x) <= val.size.x / 2f && Mathf.Abs(val2.y) <= val.size.y / 2f)
				{
					return Mathf.Abs(val2.z) <= val.size.z / 2f;
				}
				return false;
			}
			return collider.ClosestPoint(point) == point;
		}
	}
	public static class InventoryHelper
	{
		public static ItemData FindLastItem(this Inventory target, Func<ItemData, bool> predicate)
		{
			if (target.m_inventory.Count == 0)
			{
				return null;
			}
			for (int num = target.m_height - 1; num >= 0; num--)
			{
				for (int num2 = target.m_width - 1; num2 >= 0; num2--)
				{
					ItemData itemAt = target.GetItemAt(num2, num);
					if (itemAt != null && predicate(itemAt))
					{
						return itemAt;
					}
				}
			}
			return null;
		}

		public static IEnumerable<ItemData> GetItemInReverseOrder(this Inventory target)
		{
			if (target.m_inventory.Count == 0)
			{
				yield break;
			}
			for (int y = target.m_height - 1; y >= 0; y--)
			{
				for (int x = target.m_width - 1; x >= 0; x--)
				{
					ItemData itemAt = target.GetItemAt(x, y);
					if (itemAt != null)
					{
						yield return itemAt;
					}
				}
			}
		}

		public static int GetRoomForItem(this Inventory target, ItemData itemData)
		{
			int num = 0;
			foreach (ItemData item in target.m_inventory)
			{
				if (item.m_shared.m_name == itemData.m_shared.m_name)
				{
					num += Math.Max(0, item.m_shared.m_maxStackSize - item.m_stack);
				}
			}
			return num + target.GetEmptySlots() * itemData.m_shared.m_maxStackSize;
		}
	}
	public static class ItemHelper
	{
		private static readonly Dictionary<string, Vector3> ItemOffsetCache = new Dictionary<string, Vector3>();

		public static Vector3 GetVisualItemOffset(string name)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (ItemOffsetCache.TryGetValue(name, out var value))
			{
				return value;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(StringExtensionMethods.GetStableHashCode(name));
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				Logger.LogWarning((object)("Could not find item " + name + " for offset calculation"));
				ItemOffsetCache[name] = Vector3.zero;
				return ItemOffsetCache[name];
			}
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(1000f, 1000f, 1000f);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(-1000f, -1000f, -1000f);
			Vector3 position = itemPrefab.transform.position;
			Renderer[] componentsInChildren = itemPrefab.GetComponentsInChildren<Renderer>();
			foreach (Renderer val3 in componentsInChildren)
			{
				if (!(val3 is ParticleSystemRenderer))
				{
					Vector3 val4 = val;
					Bounds bounds = val3.bounds;
					val = Vector3.Min(val4, position - ((Bounds)(ref bounds)).min);
					Vector3 val5 = val2;
					bounds = val3.bounds;
					val2 = Vector3.Max(val5, position - ((Bounds)(ref bounds)).max);
				}
			}
			value = (val + val2) / 2f;
			ItemOffsetCache[name] = value;
			return value;
		}

		public static void CheckDropPrefab(ItemDrop itemDrop)
		{
			if (!Object.op_Implicit((Object)(object)itemDrop.m_itemData.m_dropPrefab))
			{
				itemDrop.m_itemData.m_dropPrefab = ObjectDB.instance.GetItemPrefab(itemDrop.GetPrefabName(((Object)((Component)itemDrop).gameObject).name));
			}
		}
	}
	public static class SnappointHelper
	{
		public static void AddSnappoints(string name, Vector3[] points)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = PrefabManager.Instance.GetPrefab(name);
			if ((Object)(object)prefab == (Object)null)
			{
				Logger.LogWarning((object)(name + " not found. Cannot add snappoints"));
				return;
			}
			for (int i = 0; i < points.Length; i++)
			{
				CreateSnappoint(points[i], prefab.transform);
			}
		}

		private static void CreateSnappoint(Vector3 pos, Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("_snappoint");
			val.transform.parent = parent;
			val.transform.localPosition = pos;
			val.tag = "snappoint";
			val.SetActive(false);
			if (Plugin.ShowSnappointHighlights.Value)
			{
				GameObject val2 = new GameObject("_snappoint_visual");
				val2.transform.parent = val.transform;
				val2.transform.localPosition = Vector3.zero;
				val2.AddComponent<SnappointVisualizer>();
			}
		}

		public static void FixPiece(string name)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(name);
			if ((Object)(object)prefab == (Object)null)
			{
				Logger.LogWarning((object)(name + " not found. Cannot fix piece snappoints"));
				return;
			}
			int num = LayerMask.NameToLayer("piece_nonsolid");
			if (num == -1)
			{
				Logger.LogError((object)"Layer 'piece_nonsolid' not found!");
				return;
			}
			Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>();
			foreach (Transform val in componentsInChildren)
			{
				if (((Component)val).CompareTag("snappoint"))
				{
					((Component)val).gameObject.layer = num;
				}
			}
		}
	}
	public class SnappointVisualizer : MonoBehaviour
	{
		private LineRenderer lineRenderer;

		private static Material lineMaterial;

		private void Awake()
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: 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_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			lineRenderer = ((Component)this).gameObject.AddComponent<LineRenderer>();
			lineRenderer.startWidth = 0.02f;
			lineRenderer.endWidth = 0.02f;
			lineRenderer.useWorldSpace = false;
			lineRenderer.loop = true;
			lineRenderer.positionCount = 16;
			if ((Object)(object)lineMaterial == (Object)null)
			{
				lineMaterial = new Material(Shader.Find("Sprites/Default"));
			}
			((Renderer)lineRenderer).material = lineMaterial;
			lineRenderer.startColor = Color.cyan;
			lineRenderer.endColor = Color.cyan;
			float num = 0.1f;
			Vector3[] array = (Vector3[])(object)new Vector3[16];
			array[0] = new Vector3(0f - num, 0f - num, 0f - num);
			array[1] = new Vector3(num, 0f - num, 0f - num);
			array[2] = new Vector3(num, 0f - num, num);
			array[3] = new Vector3(0f - num, 0f - num, num);
			array[4] = array[0];
			array[5] = new Vector3(0f - num, num, 0f - num);
			array[6] = new Vector3(num, num, 0f - num);
			array[7] = new Vector3(num, num, num);
			array[8] = new Vector3(0f - num, num, num);
			array[9] = array[5];
			array[10] = new Vector3(0f - num, num, num);
			array[11] = new Vector3(0f - num, 0f - num, num);
			array[12] = new Vector3(num, 0f - num, num);
			array[13] = new Vector3(num, num, num);
			array[14] = new Vector