Decompiled source of CraftManager v1.0.2

BepInEx/plugins/CraftManager/CraftManager.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CraftManager
{
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	internal static class CraftingUiPatch
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__DecreaseRequestedCraftCount;

			public static UnityAction <1>__IncreaseRequestedCraftCount;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__19_0;

			internal void <CreateToggleButton>b__19_0()
			{
				SetModControlsVisible(!_modControlsVisible);
			}
		}

		private const string ButtonObjectName = "CraftManagerGetMaterialsButton";

		private const int MinimumCraftCount = 1;

		private const int MaximumCraftCount = 99;

		private static int _requestedCraftCount = 1;

		private static Button? _getMaterialsButton;

		private static GameObject? _craftActionButtonObject;

		private static GameObject? _decreaseButtonObject;

		private static GameObject? _increaseButtonObject;

		private static readonly List<GameObject> ModControls = new List<GameObject>();

		private static bool _modControlsVisible;

		private static void Postfix(InventoryGui __instance)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			Button value = Traverse.Create((object)__instance).Field<Button>("m_craftButton").Value;
			RectTransform val = (RectTransform)(((Object)(object)value == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)value == (Object)null || (Object)(object)val == (Object)null || (Object)(object)((Transform)val).Find("CraftManagerGetMaterialsButton") != (Object)null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)value).gameObject, (Transform)(object)val);
			((Object)val2).name = "CraftManagerGetMaterialsButton";
			DisableLayoutComponents(val2);
			RectTransform component = ((Component)value).GetComponent<RectTransform>();
			RectTransform component2 = val2.GetComponent<RectTransform>();
			Rect rect = component.rect;
			float num = ((Rect)(ref rect)).width - 124f;
			float num2 = (num - 4f) / 2f;
			Vector3 position = ((Transform)component).position;
			rect = component.rect;
			Vector3 val3 = position + new Vector3(0f, 0f - (((Rect)(ref rect)).height + 2f), 0f);
			rect = component.rect;
			SetFixedButtonAnchors(component2, num2, ((Rect)(ref rect)).height);
			((Transform)component2).position = val3 + new Vector3(0f - (num2 / 2f + 2f), 0f, 0f);
			Button component3 = val2.GetComponent<Button>();
			((UnityEventBase)component3.onClick).RemoveAllListeners();
			((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
			{
				CraftManagerService.TryGetMaterials(__instance, _requestedCraftCount);
			});
			_getMaterialsButton = component3;
			ModControls.Add(val2);
			UpdateGetMaterialsLabel();
			rect = component.rect;
			CreateCraftButton(value, val, val3, num2, ((Rect)(ref rect)).height, __instance);
			object obj = <>O.<0>__DecreaseRequestedCraftCount;
			if (obj == null)
			{
				UnityAction val4 = DecreaseRequestedCraftCount;
				<>O.<0>__DecreaseRequestedCraftCount = val4;
				obj = (object)val4;
			}
			CreateQuantityButton(value, val, val3, num, "CraftManagerDecreaseButton", "−", -1f, (UnityAction)obj);
			object obj2 = <>O.<1>__IncreaseRequestedCraftCount;
			if (obj2 == null)
			{
				UnityAction val5 = IncreaseRequestedCraftCount;
				<>O.<1>__IncreaseRequestedCraftCount = val5;
				obj2 = (object)val5;
			}
			CreateQuantityButton(value, val, val3, num, "CraftManagerIncreaseButton", "+", 1f, (UnityAction)obj2);
			Button value2 = Traverse.Create((object)__instance).Field<Button>("m_repairButton").Value;
			if ((Object)(object)value2 != (Object)null)
			{
				RectTransform val6 = CreateToggleButton(value2, value);
				if ((Object)(object)val6 != (Object)null)
				{
					PositionControlsAsSideMenu(val6);
				}
			}
			SetModControlsVisible(visible: false);
		}

		private static void CreateCraftButton(Button template, RectTransform controlsRoot, Vector3 actionRowPosition, float width, float height, InventoryGui gui)
		{
			//IL_003b: 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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)controlsRoot);
			((Object)val).name = "CraftManagerCraftButton";
			DisableLayoutComponents(val);
			RectTransform component = val.GetComponent<RectTransform>();
			SetFixedButtonAnchors(component, width, height);
			((Transform)component).position = actionRowPosition + new Vector3(width / 2f + 2f, 0f, 0f);
			Button component2 = val.GetComponent<Button>();
			((UnityEventBase)component2.onClick).RemoveAllListeners();
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				CraftManagerService.CraftSelectedRecipe(gui, _requestedCraftCount);
			});
			ModControls.Add(val);
			_craftActionButtonObject = val;
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			for (int num = 0; num < componentsInChildren.Length; num++)
			{
				componentsInChildren[num].text = "Craft";
			}
		}

		private static void CreateQuantityButton(Button template, RectTransform controlsRoot, Vector3 actionRowPosition, float actionAreaWidth, string objectName, string labelText, float side, UnityAction onClick)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)controlsRoot);
			((Object)val).name = objectName;
			DisableLayoutComponents(val);
			RectTransform component = val.GetComponent<RectTransform>();
			SetFixedButtonAnchors(component, 52f, 72f);
			float num = side * ((actionAreaWidth + 52f) / 2f + 6f);
			((Transform)component).position = actionRowPosition + new Vector3(num, 0f, 0f);
			Button component2 = val.GetComponent<Button>();
			((UnityEventBase)component2.onClick).RemoveAllListeners();
			((UnityEvent)component2.onClick).AddListener(onClick);
			ModControls.Add(val);
			if (side < 0f)
			{
				_decreaseButtonObject = val;
			}
			else
			{
				_increaseButtonObject = val;
			}
			TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = labelText;
			}
		}

		private static void DisableLayoutComponents(GameObject buttonObject)
		{
			LayoutElement[] components = buttonObject.GetComponents<LayoutElement>();
			for (int i = 0; i < components.Length; i++)
			{
				((Behaviour)components[i]).enabled = false;
			}
			ContentSizeFitter[] components2 = buttonObject.GetComponents<ContentSizeFitter>();
			for (int i = 0; i < components2.Length; i++)
			{
				((Behaviour)components2[i]).enabled = false;
			}
		}

		private static void SetFixedButtonAnchors(RectTransform buttonTransform, float width, float height)
		{
			//IL_000b: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			buttonTransform.anchorMin = new Vector2(0.5f, 0.5f);
			buttonTransform.anchorMax = new Vector2(0.5f, 0.5f);
			buttonTransform.pivot = new Vector2(0.5f, 0.5f);
			buttonTransform.SetSizeWithCurrentAnchors((Axis)0, width);
			buttonTransform.SetSizeWithCurrentAnchors((Axis)1, height);
		}

		private static void DecreaseRequestedCraftCount()
		{
			_requestedCraftCount = Mathf.Max(1, _requestedCraftCount - 1);
			UpdateGetMaterialsLabel();
		}

		private static void IncreaseRequestedCraftCount()
		{
			_requestedCraftCount = Mathf.Min(99, _requestedCraftCount + 1);
			UpdateGetMaterialsLabel();
		}

		private static void UpdateGetMaterialsLabel()
		{
			if (!((Object)(object)_getMaterialsButton == (Object)null))
			{
				TMP_Text[] componentsInChildren = ((Component)_getMaterialsButton).GetComponentsInChildren<TMP_Text>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					componentsInChildren[i].text = $"Get Materials x{_requestedCraftCount}";
				}
			}
		}

		internal static void ResetRequestedCraftCount()
		{
			_requestedCraftCount = 1;
			UpdateGetMaterialsLabel();
			SetModControlsVisible(visible: false);
		}

		private static RectTransform? CreateToggleButton(Button repairButton, Button textTemplate)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = ((Component)repairButton).transform.parent;
			if ((Object)(object)parent == (Object)null || (Object)(object)parent.Find("CraftManagerToggleButton") != (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)repairButton).gameObject, parent);
			((Object)val).name = "CraftManagerToggleButton";
			DisableLayoutComponents(val);
			RectTransform component = ((Component)repairButton).GetComponent<RectTransform>();
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.anchorMin = component.anchorMin;
			component2.anchorMax = component.anchorMax;
			component2.pivot = component.pivot;
			Rect rect = component.rect;
			component2.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width);
			rect = component.rect;
			component2.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height);
			Vector3 position = ((Transform)component).position;
			rect = component.rect;
			((Transform)component2).position = position - new Vector3(0f, ((Rect)(ref rect)).height + 6f, 0f);
			Button component3 = val.GetComponent<Button>();
			((UnityEventBase)component3.onClick).RemoveAllListeners();
			ButtonClickedEvent onClick = component3.onClick;
			object obj = <>c.<>9__19_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					SetModControlsVisible(!_modControlsVisible);
				};
				<>c.<>9__19_0 = val2;
				obj = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			UITooltip component4 = val.GetComponent<UITooltip>();
			if ((Object)(object)component4 != (Object)null)
			{
				Traverse.Create((object)component4).Field("m_text").SetValue((object)"Show/hide Craft Manager storage controls");
			}
			Image[] componentsInChildren = val.GetComponentsInChildren<Image>(true);
			foreach (Image val3 in componentsInChildren)
			{
				if ((Object)(object)((Component)val3).gameObject != (Object)(object)val)
				{
					((Behaviour)val3).enabled = false;
				}
			}
			TMP_Text val4 = ((Component)textTemplate).GetComponentsInChildren<TMP_Text>(true).FirstOrDefault();
			if ((Object)(object)val4 == (Object)null)
			{
				return component2;
			}
			GameObject obj2 = Object.Instantiate<GameObject>(((Component)val4).gameObject, val.transform);
			DisableLayoutComponents(obj2);
			RectTransform component5 = obj2.GetComponent<RectTransform>();
			component5.anchorMin = Vector2.zero;
			component5.anchorMax = Vector2.one;
			component5.offsetMin = Vector2.zero;
			component5.offsetMax = Vector2.zero;
			TMP_Text component6 = obj2.GetComponent<TMP_Text>();
			component6.text = "▣";
			component6.alignment = (TextAlignmentOptions)514;
			component6.fontSize = 32f;
			return component2;
		}

		private static void PositionControlsAsSideMenu(RectTransform toggleTransform)
		{
			//IL_0062: 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_0072: 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_008c: 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_00aa: 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_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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_018a: 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_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_getMaterialsButton == (Object)null) && !((Object)(object)_craftActionButtonObject == (Object)null) && !((Object)(object)_decreaseButtonObject == (Object)null) && !((Object)(object)_increaseButtonObject == (Object)null))
			{
				RectTransform component = ((Component)_getMaterialsButton).GetComponent<RectTransform>();
				RectTransform component2 = _craftActionButtonObject.GetComponent<RectTransform>();
				RectTransform component3 = _decreaseButtonObject.GetComponent<RectTransform>();
				RectTransform component4 = _increaseButtonObject.GetComponent<RectTransform>();
				float x = ((Transform)toggleTransform).position.x;
				Rect rect = toggleTransform.rect;
				float num = x + ((Rect)(ref rect)).width / 2f;
				rect = component.rect;
				float num2 = num - ((Rect)(ref rect)).width / 2f;
				float y = ((Transform)toggleTransform).position.y;
				rect = toggleTransform.rect;
				float num3 = y - ((Rect)(ref rect)).height / 2f - 5f;
				rect = component.rect;
				float num4 = num3 - ((Rect)(ref rect)).height / 2f;
				rect = component.rect;
				float num5 = num4 - ((Rect)(ref rect)).height / 2f - 5f;
				rect = component2.rect;
				float num6 = num5 - ((Rect)(ref rect)).height / 2f;
				rect = component2.rect;
				float num7 = num6 - ((Rect)(ref rect)).height / 2f - 5f;
				rect = component3.rect;
				float num8 = num7 - ((Rect)(ref rect)).height / 2f;
				((Transform)component).position = new Vector3(num2, num4, 0f);
				((Transform)component2).position = new Vector3(num2, num6, 0f);
				rect = component.rect;
				float num9 = num - ((Rect)(ref rect)).width;
				rect = component3.rect;
				((Transform)component3).position = new Vector3(num9 + ((Rect)(ref rect)).width / 2f, num8, 0f);
				rect = component4.rect;
				((Transform)component4).position = new Vector3(num - ((Rect)(ref rect)).width / 2f, num8, 0f);
			}
		}

		private static void SetModControlsVisible(bool visible)
		{
			_modControlsVisible = visible;
			foreach (GameObject modControl in ModControls)
			{
				if ((Object)(object)modControl != (Object)null)
				{
					modControl.SetActive(visible);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
	internal static class CraftingMaterialTotalsPatch
	{
		private static readonly Regex QuantityLabelPattern = new Regex("^\\d+(?:/\\d+)?$");

		private static readonly Regex ExistingTotalPattern = new Regex("/\\d+$");

		private static readonly Regex RichTextTagPattern = new Regex("<.*?>");

		private static readonly Regex RequiredAmountPattern = new Regex("^\\d+");

		private static void Postfix(InventoryGui __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			Recipe val = (((Object)(object)localPlayer == (Object)null) ? null : CraftManagerService.GetSelectedRecipe(__instance));
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)val == (Object)null)
			{
				return;
			}
			GameObject[] value = Traverse.Create((object)__instance).Field<GameObject[]>("m_recipeRequirementList").Value;
			if (value == null)
			{
				return;
			}
			IReadOnlyDictionary<string, int> nearbyStoredItemTotals = CraftManagerService.GetNearbyStoredItemTotals(localPlayer);
			Requirement[] array = val.m_resources.Where((Requirement requirement) => (Object)(object)requirement?.m_resItem != (Object)null).ToArray();
			foreach (Requirement val2 in array)
			{
				string itemName = val2.m_resItem.m_itemData.m_shared.m_name;
				string localizedItemName = Localization.instance.Localize(itemName);
				GameObject val3 = ((IEnumerable<GameObject>)value).FirstOrDefault((Func<GameObject, bool>)((GameObject candidate) => (Object)(object)candidate != (Object)null && candidate.GetComponentsInChildren<TMP_Text>(true).Any((TMP_Text label) => RichTextTagPattern.Replace(label.text, string.Empty) == localizedItemName)));
				if ((Object)(object)val3 == (Object)null)
				{
					continue;
				}
				nearbyStoredItemTotals.TryGetValue(itemName, out var value2);
				int num2 = (from item in ((Humanoid)localPlayer).GetInventory().GetAllItems()
					where item.m_shared.m_name == itemName
					select item).Sum((ItemData item) => item.m_stack);
				TMP_Text val4 = ((IEnumerable<TMP_Text>)val3.GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text label) => QuantityLabelPattern.IsMatch(RichTextTagPattern.Replace(label.text, string.Empty))));
				if (!((Object)(object)val4 == (Object)null))
				{
					string input = RichTextTagPattern.Replace(val4.text, string.Empty);
					input = ExistingTotalPattern.Replace(input, string.Empty);
					Match match = RequiredAmountPattern.Match(input);
					if (match.Success && int.TryParse(match.Value, out var result))
					{
						string arg = ((num2 >= result) ? "white" : ((num2 + value2 >= result) ? "#FFD24A" : "#FF5555"));
						val4.text = $"<color={arg}>{result}</color>/<color=white>{value2}</color>";
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
	internal static class HammerMaterialTotalsPatch
	{
		private static readonly Regex QuantityLabelPattern = new Regex("^\\d+(?:/\\d+)?$");

		private static readonly Regex ExistingTotalPattern = new Regex("/\\d+$");

		private static readonly Regex RichTextTagPattern = new Regex("<.*?>");

		private static readonly Regex RequiredAmountPattern = new Regex("^\\d+");

		private static void Postfix(Hud __instance, Piece piece)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)piece == (Object)null)
			{
				return;
			}
			GameObject[] value = Traverse.Create((object)__instance).Field<GameObject[]>("m_requirementItems").Value;
			if (value == null)
			{
				return;
			}
			IReadOnlyDictionary<string, int> nearbyStoredItemTotals = CraftManagerService.GetNearbyStoredItemTotals(localPlayer);
			Requirement[] array = piece.m_resources.Where((Requirement requirement) => (Object)(object)requirement?.m_resItem != (Object)null).ToArray();
			foreach (Requirement val in array)
			{
				string itemName = val.m_resItem.m_itemData.m_shared.m_name;
				string localizedItemName = Localization.instance.Localize(itemName);
				GameObject val2 = ((IEnumerable<GameObject>)value).FirstOrDefault((Func<GameObject, bool>)((GameObject candidate) => (Object)(object)candidate != (Object)null && candidate.GetComponentsInChildren<TMP_Text>(true).Any((TMP_Text label) => RichTextTagPattern.Replace(label.text, string.Empty) == localizedItemName)));
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				nearbyStoredItemTotals.TryGetValue(itemName, out var value2);
				int num2 = (from item in ((Humanoid)localPlayer).GetInventory().GetAllItems()
					where item.m_shared.m_name == itemName
					select item).Sum((ItemData item) => item.m_stack);
				TMP_Text val3 = ((IEnumerable<TMP_Text>)val2.GetComponentsInChildren<TMP_Text>(true)).FirstOrDefault((Func<TMP_Text, bool>)((TMP_Text label) => QuantityLabelPattern.IsMatch(RichTextTagPattern.Replace(label.text, string.Empty))));
				if (!((Object)(object)val3 == (Object)null))
				{
					string input = ExistingTotalPattern.Replace(RichTextTagPattern.Replace(val3.text, string.Empty), string.Empty);
					Match match = RequiredAmountPattern.Match(input);
					if (match.Success && int.TryParse(match.Value, out var result))
					{
						string arg = ((num2 >= result) ? "white" : ((num2 + value2 >= result) ? "#FFD24A" : "#FF5555"));
						val3.text = $"<color={arg}>{result}</color>/<color=white>{value2}</color>";
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Hide")]
	internal static class CraftingUiClosePatch
	{
		private static void Postfix()
		{
			CraftingUiPatch.ResetRequestedCraftCount();
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	internal static class ContainerSortUiPatch
	{
		private const string SortButtonObjectName = "CraftManagerSortButton";

		private static void Postfix(InventoryGui __instance)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_00aa: 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_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_00d2: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			Button value = Traverse.Create((object)__instance).Field<Button>("m_takeAllButton").Value;
			if (!((Object)(object)value == (Object)null) && !((Object)(object)((Component)value).transform.parent.Find("CraftManagerSortButton") != (Object)null))
			{
				GameObject obj = Object.Instantiate<GameObject>(((Component)value).gameObject, ((Component)value).transform.parent);
				((Object)obj).name = "CraftManagerSortButton";
				DisableLayoutComponents(obj);
				RectTransform component = ((Component)value).GetComponent<RectTransform>();
				RectTransform component2 = obj.GetComponent<RectTransform>();
				component2.anchorMin = component.anchorMin;
				component2.anchorMax = component.anchorMax;
				component2.pivot = component.pivot;
				Rect rect = component.rect;
				component2.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width);
				rect = component.rect;
				component2.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height);
				Vector3 position = ((Transform)component).position;
				rect = component.rect;
				((Transform)component2).position = position - new Vector3(0f, ((Rect)(ref rect)).height + 6f, 0f);
				Button component3 = obj.GetComponent<Button>();
				((UnityEventBase)component3.onClick).RemoveAllListeners();
				((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
				{
					CraftManagerService.SortOpenContainer(__instance);
				});
				TMP_Text[] componentsInChildren = obj.GetComponentsInChildren<TMP_Text>(true);
				for (int num = 0; num < componentsInChildren.Length; num++)
				{
					componentsInChildren[num].text = "Sort";
				}
			}
		}

		private static void DisableLayoutComponents(GameObject buttonObject)
		{
			LayoutElement[] components = buttonObject.GetComponents<LayoutElement>();
			for (int i = 0; i < components.Length; i++)
			{
				((Behaviour)components[i]).enabled = false;
			}
			ContentSizeFitter[] components2 = buttonObject.GetComponents<ContentSizeFitter>();
			for (int i = 0; i < components2.Length; i++)
			{
				((Behaviour)components2[i]).enabled = false;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	internal static class TrashSlotUiPatch
	{
		private const string TrashObjectName = "CraftManagerTrashSlot";

		internal static RectTransform? TrashTransform { get; private set; }

		private static void Postfix(InventoryGui __instance)
		{
			//IL_00bc: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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_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_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text value = Traverse.Create((object)__instance).Field<TMP_Text>("m_weight").Value;
			Button value2 = Traverse.Create((object)__instance).Field<Button>("m_repairButton").Value;
			Button value3 = Traverse.Create((object)__instance).Field<Button>("m_takeAllButton").Value;
			if ((Object)(object)value == (Object)null || (Object)(object)value2 == (Object)null || (Object)(object)value3 == (Object)null || (Object)(object)value.transform.parent.Find("CraftManagerTrashSlot") != (Object)null)
			{
				return;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)value2).gameObject, value.transform.parent);
			((Object)val).name = "CraftManagerTrashSlot";
			ContainerSortUiPatchDisableLayout(val);
			RectTransform component = ((Component)value).GetComponent<RectTransform>();
			RectTransform component2 = ((Component)value2).GetComponent<RectTransform>();
			RectTransform component3 = val.GetComponent<RectTransform>();
			component3.anchorMin = component.anchorMin;
			component3.anchorMax = component.anchorMax;
			component3.pivot = component.pivot;
			Rect rect = component2.rect;
			component3.SetSizeWithCurrentAnchors((Axis)0, ((Rect)(ref rect)).width);
			rect = component2.rect;
			component3.SetSizeWithCurrentAnchors((Axis)1, ((Rect)(ref rect)).height);
			((Transform)component3).position = ((Transform)component).position + new Vector3(0f, 85f, 0f);
			TrashTransform = component3;
			((UnityEventBase)val.GetComponent<Button>().onClick).RemoveAllListeners();
			UITooltip component4 = val.GetComponent<UITooltip>();
			if ((Object)(object)component4 != (Object)null)
			{
				Traverse.Create((object)component4).Field("m_text").SetValue((object)"Permanently delete a dragged item");
			}
			Image[] componentsInChildren = val.GetComponentsInChildren<Image>(true);
			foreach (Image val2 in componentsInChildren)
			{
				if ((Object)(object)((Component)val2).gameObject != (Object)(object)val)
				{
					((Behaviour)val2).enabled = false;
				}
			}
			TMP_Text val3 = ((Component)value3).GetComponentsInChildren<TMP_Text>(true).FirstOrDefault();
			if (!((Object)(object)val3 == (Object)null))
			{
				GameObject obj = Object.Instantiate<GameObject>(((Component)val3).gameObject, val.transform);
				ContainerSortUiPatchDisableLayout(obj);
				RectTransform component5 = obj.GetComponent<RectTransform>();
				component5.anchorMin = Vector2.zero;
				component5.anchorMax = Vector2.one;
				component5.offsetMin = Vector2.zero;
				component5.offsetMax = Vector2.zero;
				TMP_Text component6 = obj.GetComponent<TMP_Text>();
				component6.text = string.Empty;
				component6.alignment = (TextAlignmentOptions)514;
				component6.fontSize = 34f;
				CreateTrashBinIcon(val.transform);
				CreateEmptyButton(value, value3, __instance);
			}
		}

		private static void CreateEmptyButton(TMP_Text weightLabel, Button template, InventoryGui gui)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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)
			//IL_00df: Expected O, but got Unknown
			Transform parent = weightLabel.transform.parent;
			if (!((Object)(object)parent.Find("CraftManagerEmptyButton") != (Object)null))
			{
				GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, parent);
				((Object)val).name = "CraftManagerEmptyButton";
				ContainerSortUiPatchDisableLayout(val);
				RectTransform component = ((Component)weightLabel).GetComponent<RectTransform>();
				RectTransform component2 = val.GetComponent<RectTransform>();
				component2.anchorMin = component.anchorMin;
				component2.anchorMax = component.anchorMax;
				component2.pivot = component.pivot;
				component2.SetSizeWithCurrentAnchors((Axis)0, 68f);
				component2.SetSizeWithCurrentAnchors((Axis)1, 29f);
				((Transform)component2).position = ((Transform)component).position + new Vector3(5f, -48f, 0f);
				Button component3 = val.GetComponent<Button>();
				((UnityEventBase)component3.onClick).RemoveAllListeners();
				((UnityEvent)component3.onClick).AddListener((UnityAction)delegate
				{
					CraftManagerService.EmptyInventoryIntoExistingStacks(gui);
				});
				TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true);
				foreach (TMP_Text obj in componentsInChildren)
				{
					obj.text = "Empty";
					obj.fontSize = 18f;
				}
				UITooltip component4 = val.GetComponent<UITooltip>();
				if ((Object)(object)component4 != (Object)null)
				{
					Traverse.Create((object)component4).Field("m_text").SetValue((object)"Move non-hotbar, non-equipped items into matching nearby storage stacks");
				}
			}
		}

		private static void CreateTrashBinIcon(Transform parent)
		{
			//IL_0050: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_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_00e4: 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)
			Color color = default(Color);
			((Color)(ref color))..ctor(0.94f, 0.63f, 0.18f, 1f);
			Color color2 = default(Color);
			((Color)(ref color2))..ctor(0.36f, 0.2f, 0.06f, 1f);
			CreateIconPart(parent, "BinBody", 20f, 23f, new Vector2(0f, -3f), color);
			CreateIconPart(parent, "BinLid", 25f, 4f, new Vector2(0f, 11f), color);
			CreateIconPart(parent, "BinHandle", 9f, 4f, new Vector2(0f, 15f), color);
			CreateIconPart(parent, "BinLineLeft", 2f, 15f, new Vector2(-5f, -4f), color2);
			CreateIconPart(parent, "BinLineRight", 2f, 15f, new Vector2(5f, -4f), color2);
		}

		private static void CreateIconPart(Transform parent, string name, float width, float height, Vector2 position, Color color)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_0051: 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_007b: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0.5f, 0.5f);
			component.anchorMax = new Vector2(0.5f, 0.5f);
			component.pivot = new Vector2(0.5f, 0.5f);
			component.anchoredPosition = position;
			component.SetSizeWithCurrentAnchors((Axis)0, width);
			component.SetSizeWithCurrentAnchors((Axis)1, height);
			((Graphic)val.GetComponent<Image>()).color = color;
		}

		private static void ContainerSortUiPatchDisableLayout(GameObject objectToAdjust)
		{
			LayoutElement[] components = objectToAdjust.GetComponents<LayoutElement>();
			for (int i = 0; i < components.Length; i++)
			{
				((Behaviour)components[i]).enabled = false;
			}
			ContentSizeFitter[] components2 = objectToAdjust.GetComponents<ContentSizeFitter>();
			for (int i = 0; i < components2.Length; i++)
			{
				((Behaviour)components2[i]).enabled = false;
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateItemDrag")]
	internal static class TrashSlotDropPatch
	{
		private static bool Prefix(InventoryGui __instance)
		{
			if (!Input.GetMouseButtonUp(0))
			{
				return true;
			}
			return !TryDeleteDraggedItem(__instance);
		}

		private static bool TryDeleteDraggedItem(InventoryGui __instance)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			RectTransform trashTransform = TrashSlotUiPatch.TrashTransform;
			if ((Object)(object)trashTransform == (Object)null || !((Component)trashTransform).gameObject.activeInHierarchy || !RectTransformUtility.RectangleContainsScreenPoint(trashTransform, Vector2.op_Implicit(Input.mousePosition)))
			{
				return false;
			}
			Traverse val = Traverse.Create((object)__instance);
			ItemData value = val.Field<ItemData>("m_dragItem").Value;
			Inventory value2 = val.Field<Inventory>("m_dragInventory").Value;
			int value3 = val.Field<int>("m_dragAmount").Value;
			if (value == null || value2 == null || value3 <= 0)
			{
				return false;
			}
			if (!value2.RemoveItem(value, value3))
			{
				return false;
			}
			GameObject value4 = val.Field<GameObject>("m_dragGo").Value;
			if ((Object)(object)value4 != (Object)null)
			{
				Object.Destroy((Object)(object)value4);
			}
			val.Field("m_dragGo").SetValue((object)null);
			val.Field("m_dragItem").SetValue((object)null);
			val.Field("m_dragInventory").SetValue((object)null);
			val.Field("m_dragAmount").SetValue((object)0);
			val.Property("IsSplitDropping", (object[])null).SetValue((object)false);
			return true;
		}
	}
	[BepInPlugin("com.alik9.valheim.craftmanager", "Craft Manager", "1.0.2")]
	public sealed class CraftManagerPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.alik9.valheim.craftmanager";

		public const string PluginName = "Craft Manager";

		public const string PluginVersion = "1.0.2";

		internal static ConfigEntry<float> ContainerSearchRadius { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			ContainerSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Craft Manager", "Container search radius", 100f, "Maximum distance, in meters, for nearby containers. This first version searches loaded containers only.");
			new Harmony("com.alik9.valheim.craftmanager").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Craft Manager 1.0.2 loaded successfully. Crafting, storage totals, silent hammer material pulling, container sorting, trash, and inventory emptying are enabled.");
		}
	}
	internal static class CraftManagerService
	{
		private static readonly FieldInfo SelectedRecipeField = AccessTools.Field(typeof(InventoryGui), "m_selectedRecipe");

		internal static void TryGetMaterials(InventoryGui gui, int craftCount)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !gui.InCraftTab())
			{
				ShowMessage("Open the Craft tab and select a recipe first.");
				return;
			}
			Recipe selectedRecipe = GetSelectedRecipe(gui);
			if ((Object)(object)selectedRecipe == (Object)null)
			{
				ShowMessage("Select a craftable recipe first.");
				return;
			}
			int selectedQuality = GetSelectedQuality(gui);
			Dictionary<string, int> missingIngredients = GetMissingIngredients(selectedRecipe, selectedQuality, craftCount, ((Humanoid)localPlayer).GetInventory());
			if (missingIngredients.Count == 0)
			{
				ShowMessage("You already have all required materials.");
				return;
			}
			List<Container> list = FindUsableContainers(localPlayer);
			CraftManagerPlugin.Log.LogInfo((object)($"Recipe '{selectedRecipe.m_item.m_itemData.m_shared.m_name}' x{craftCount} needs: {FormatRequirements(missingIngredients)}. " + $"Accessible containers found: {list.Count}."));
			if (list.Count == 0)
			{
				ShowMessage($"No accessible containers were found within {CraftManagerPlugin.ContainerSearchRadius.Value:0} meters.");
				return;
			}
			int usedContainers;
			int num = MoveIngredients(((Humanoid)localPlayer).GetInventory(), list, missingIngredients, out usedContainers);
			if (num == 0)
			{
				ShowMessage("Nearby accessible containers were found, but none contain materials required by this recipe.");
				return;
			}
			int num2 = missingIngredients.Values.Sum();
			string text = $"Moved {num} material(s) for up to {craftCount} craft(s) from {usedContainers} container(s).";
			if (num2 > 0)
			{
				text += $" Still missing {num2}.";
			}
			Traverse.Create((object)gui).Method("UpdateCraftingPanel", new object[1] { false }).GetValue();
			ShowMessage(text);
		}

		internal static void CraftSelectedRecipe(InventoryGui gui, int craftCount)
		{
			if (!gui.InCraftTab())
			{
				ShowMessage("Open the Craft tab and select a recipe first.");
				return;
			}
			craftCount = Mathf.Max(1, craftCount);
			Recipe selectedRecipe = GetSelectedRecipe(gui);
			int selectedQuality = GetSelectedQuality(gui);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)selectedRecipe == (Object)null)
			{
				ShowCraftManagerMessage("Craft: select a recipe first.");
				return;
			}
			if (!localPlayer.HaveRequirements(selectedRecipe, false, selectedQuality, craftCount))
			{
				TryGetMaterials(gui, craftCount);
				selectedRecipe = GetSelectedRecipe(gui);
				selectedQuality = GetSelectedQuality(gui);
				if ((Object)(object)selectedRecipe == (Object)null || !localPlayer.HaveRequirements(selectedRecipe, false, selectedQuality, craftCount))
				{
					ShowCraftManagerMessage($"Craft: materials for x{craftCount} are still missing.");
					return;
				}
			}
			Traverse obj = Traverse.Create((object)gui);
			obj.Field("m_multiCraftAmount").SetValue((object)craftCount);
			obj.Field("m_touchMultiCrafting").SetValue((object)(craftCount > 1));
			obj.Method("OnCraftPressed", Array.Empty<object>()).GetValue();
		}

		internal static IReadOnlyDictionary<string, int> GetNearbyStoredItemTotals(Player player)
		{
			return (from item in (from container in FindUsableContainers(player)
					select container.GetInventory() into inventory
					where inventory != null
					select inventory).SelectMany((Inventory inventory) => inventory.GetAllItems())
				group item by item.m_shared.m_name).ToDictionary((IGrouping<string, ItemData> group) => group.Key, (IGrouping<string, ItemData> group) => group.Sum((ItemData item) => item.m_stack));
		}

		internal static void SortOpenContainer(InventoryGui gui)
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			Container value = Traverse.Create((object)gui).Field<Container>("m_currentContainer").Value;
			if (!((Object)(object)value == (Object)null))
			{
				Inventory inventory = value.GetInventory();
				List<ItemData> list = inventory.GetAllItems().OrderBy<ItemData, string>((ItemData item) => Localization.instance.Localize(item.m_shared.m_name), StringComparer.CurrentCultureIgnoreCase).ThenBy((ItemData item) => item.m_quality)
					.ThenBy((ItemData item) => item.m_variant)
					.ToList();
				int width = inventory.GetWidth();
				for (int num = 0; num < list.Count; num++)
				{
					list[num].m_gridPos = new Vector2i(num % width, num / width);
				}
				Traverse.Create((object)inventory).Method("Changed", new object[2] { true, false }).GetValue();
				Traverse.Create((object)value).Method("Save", Array.Empty<object>()).GetValue();
				Traverse.Create((object)gui).Method("UpdateContainer", new object[1] { Player.m_localPlayer }).GetValue();
			}
		}

		internal static void EmptyInventoryIntoExistingStacks(InventoryGui gui)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			List<Container> list = FindUsableContainers(localPlayer);
			HashSet<Container> hashSet = new HashSet<Container>();
			int num = 0;
			ItemData[] array = inventory.GetAllItems().ToArray();
			foreach (ItemData item in array)
			{
				if (item.m_gridPos.y == 0 || item.m_equipped)
				{
					continue;
				}
				foreach (Container item2 in list)
				{
					if (item.m_stack <= 0)
					{
						break;
					}
					Inventory inventory2 = item2.GetInventory();
					if (inventory2 == null || !inventory2.GetAllItems().Any((ItemData storedItem) => storedItem.m_shared.m_name == item.m_shared.m_name))
					{
						continue;
					}
					int largestTransferableAmount = GetLargestTransferableAmount(inventory2, item);
					if (largestTransferableAmount > 0)
					{
						ItemData val = item.Clone();
						val.m_stack = largestTransferableAmount;
						if (inventory2.AddItem(val))
						{
							inventory.RemoveItem(item, largestTransferableAmount);
							num += largestTransferableAmount;
							hashSet.Add(item2);
						}
					}
				}
			}
			foreach (Container item3 in hashSet)
			{
				Traverse.Create((object)item3.GetInventory()).Method("Changed", new object[2] { true, false }).GetValue();
				Traverse.Create((object)item3).Method("Save", Array.Empty<object>()).GetValue();
			}
			Traverse.Create((object)gui).Method("UpdateInventory", new object[1] { localPlayer }).GetValue();
			if (num == 0)
			{
				ShowCraftManagerMessage("Empty: no matching nearby storage stacks were available.");
			}
			else
			{
				ShowCraftManagerMessage($"Empty: moved {num} item(s) into matching stacks in {hashSet.Count} nearby container(s).");
			}
		}

		internal static void PullMaterialsForPlacement(Player player, Piece piece)
		{
			if ((Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)piece == (Object)null)
			{
				return;
			}
			Dictionary<string, int> missingRequirements = GetMissingRequirements(piece.m_resources, 1, 1, ((Humanoid)player).GetInventory(), skipUpgraderResources: false);
			if (missingRequirements.Count == 0)
			{
				CraftManagerPlugin.Log.LogInfo((object)("Hammer placement '" + piece.m_name + "': all materials are already carried."));
				return;
			}
			List<Container> list = FindUsableContainers(player);
			CraftManagerPlugin.Log.LogInfo((object)("Hammer placement '" + piece.m_name + "' needs " + FormatRequirements(missingRequirements) + ". " + $"Accessible containers found: {list.Count}."));
			if (list.Count != 0)
			{
				int usedContainers;
				int num = MoveIngredients(((Humanoid)player).GetInventory(), list, missingRequirements, out usedContainers);
				CraftManagerPlugin.Log.LogInfo((object)($"Hammer placement '{piece.m_name}': moved {num} material(s) from {usedContainers} container(s). " + "Still needed: " + FormatRequirements(missingRequirements) + "."));
			}
		}

		internal static Recipe? GetSelectedRecipe(InventoryGui gui)
		{
			object value = SelectedRecipeField.GetValue(gui);
			if (value == null)
			{
				return null;
			}
			return Traverse.Create(value).Property<Recipe>("Recipe", (object[])null).Value;
		}

		private static int GetSelectedQuality(InventoryGui gui)
		{
			object value = SelectedRecipeField.GetValue(gui);
			return ((value == null) ? null : Traverse.Create(value).Property<ItemData>("ItemData", (object[])null).Value)?.m_quality ?? 1;
		}

		private static Dictionary<string, int> GetMissingIngredients(Recipe recipe, int quality, int craftCount, Inventory playerInventory)
		{
			return GetMissingRequirements(recipe.m_resources, quality, craftCount, playerInventory, skipUpgraderResources: true);
		}

		private static Dictionary<string, int> GetMissingRequirements(IEnumerable<Requirement> requirements, int quality, int multiplier, Inventory playerInventory, bool skipUpgraderResources)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (Requirement item in requirements ?? Array.Empty<Requirement>())
			{
				if (!((Object)(object)item?.m_resItem == (Object)null) && (!skipUpgraderResources || !item.m_upgraderResource))
				{
					string name = item.m_resItem.m_itemData.m_shared.m_name;
					int num = item.GetAmount(quality) * multiplier;
					dictionary[name] = (dictionary.TryGetValue(name, out var value) ? (value + num) : num);
				}
			}
			Dictionary<string, int> dictionary2 = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				string itemName = item2.Key;
				int value2 = item2.Value;
				int num2 = (from item in playerInventory.GetAllItems()
					where item.m_shared.m_name == itemName
					select item).Sum((ItemData item) => item.m_stack);
				int num3 = Math.Max(0, value2 - num2);
				if (num3 > 0)
				{
					dictionary2[itemName] = num3;
				}
			}
			return dictionary2;
		}

		internal static List<Container> FindUsableContainers(Player player)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			float range = Mathf.Max(0f, CraftManagerPlugin.ContainerSearchRadius.Value);
			Vector3 playerPosition = ((Component)player).transform.position;
			return (from container in Object.FindObjectsByType<Container>((FindObjectsSortMode)0)
				where (Object)(object)container != (Object)null && ((Behaviour)container).isActiveAndEnabled
				where container.GetInventory() != null
				where !container.IsInUse()
				where Vector3.Distance(playerPosition, ((Component)container).transform.position) <= range
				where HasAccess(container, player.GetPlayerID())
				orderby Vector3.Distance(playerPosition, ((Component)container).transform.position)
				select container).ToList();
		}

		private static bool HasAccess(Container container, long playerId)
		{
			return Traverse.Create((object)container).Method("CheckAccess", new object[1] { playerId }).GetValue<bool>();
		}

		private static int MoveIngredients(Inventory playerInventory, IEnumerable<Container> containers, IDictionary<string, int> required, out int usedContainers)
		{
			int num = 0;
			usedContainers = 0;
			foreach (Container container in containers)
			{
				bool flag = false;
				Inventory inventory = container.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				string[] array = (from item in inventory.GetAllItems()
					where required.ContainsKey(item.m_shared.m_name)
					select $"{item.m_shared.m_name} x{item.m_stack}").ToArray();
				if (array.Length != 0)
				{
					CraftManagerPlugin.Log.LogInfo((object)("Container '" + container.GetHoverName() + "' has matching stack(s): " + string.Join(", ", array) + "."));
				}
				ItemData[] array2 = inventory.GetAllItems().ToArray();
				foreach (ItemData val in array2)
				{
					string name = val.m_shared.m_name;
					if (!required.TryGetValue(name, out var value) || value <= 0)
					{
						continue;
					}
					int num3 = Math.Min(value, val.m_stack);
					if (!playerInventory.CanAddItem(val, num3))
					{
						CraftManagerPlugin.Log.LogInfo((object)$"Player inventory has no room for {name} x{num3}.");
						continue;
					}
					ItemData val2 = val.Clone();
					val2.m_stack = num3;
					if (!playerInventory.AddItem(val2))
					{
						CraftManagerPlugin.Log.LogWarning((object)$"Valheim declined the transfer of {name} x{num3}.");
					}
					else if (!inventory.RemoveItem(val, num3))
					{
						playerInventory.RemoveItem(val2, num3);
						CraftManagerPlugin.Log.LogWarning((object)$"Source container changed before {name} x{num3} could be removed.");
					}
					else
					{
						required[name] -= num3;
						num += num3;
						flag = true;
					}
				}
				if (flag)
				{
					usedContainers++;
				}
				if (required.Values.All((int amount) => amount <= 0))
				{
					break;
				}
			}
			return num;
		}

		private static int GetLargestTransferableAmount(Inventory storageInventory, ItemData item)
		{
			for (int num = item.m_stack; num > 0; num--)
			{
				if (storageInventory.CanAddItem(item, num))
				{
					return num;
				}
			}
			return 0;
		}

		private static string FormatRequirements(IReadOnlyDictionary<string, int> requirements)
		{
			return string.Join(", ", requirements.Select<KeyValuePair<string, int>, string>((KeyValuePair<string, int> entry) => $"{entry.Key} x{entry.Value}"));
		}

		private static void ShowMessage(string message)
		{
			CraftManagerPlugin.Log.LogInfo((object)message);
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, "Get Materials: " + message, 0, (Sprite)null, false, true);
			}
		}

		private static void ShowCraftManagerMessage(string message)
		{
			CraftManagerPlugin.Log.LogInfo((object)message);
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)1, message, 0, (Sprite)null, false, true);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdatePlacement", new Type[]
	{
		typeof(bool),
		typeof(float)
	})]
	internal static class HammerBuildingPatch
	{
		private static void Prefix(Player __instance)
		{
			if (ZInput.GetButtonDown("Attack") || ZInput.GetButtonDown("JoyPlace"))
			{
				Piece selectedPiece = __instance.GetSelectedPiece();
				CraftManagerService.PullMaterialsForPlacement(__instance, selectedPiece);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "UpdateRecipe")]
	internal static class UpgradeAvailabilityPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = AccessTools.Method(typeof(Player), "HaveRequirements", new Type[4]
			{
				typeof(Recipe),
				typeof(bool),
				typeof(int),
				typeof(int)
			}, (Type[])null);
			MethodInfo replacement = AccessTools.Method(typeof(UpgradeMaterials), "HaveRequirements", (Type[])null, (Type[])null);
			int replacements = 0;
			foreach (CodeInstruction instruction in instructions)
			{
				if (CodeInstructionExtensions.Calls(instruction, original))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = replacement;
					replacements++;
				}
				yield return instruction;
			}
			if (replacements != 1)
			{
				throw new InvalidOperationException($"Expected one upgrade button requirement check, found {replacements}.");
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "CountItems", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(bool)
	})]
	internal static class UpgradeStorageCountPatch
	{
		private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
		{
			if (__instance != UpgradeMaterials.CountingInventory || UpgradeMaterials.CountingStorage == null)
			{
				return;
			}
			foreach (Inventory item in UpgradeMaterials.CountingStorage)
			{
				__result += item.CountItems(name, quality, matchWorldLevel);
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnCraftPressed")]
	internal static class NativeUpgradeButtonPatch
	{
		private static bool Prefix(InventoryGui __instance)
		{
			return UpgradeMaterials.PrepareUpgrade(__instance);
		}
	}
	internal static class UpgradeMaterials
	{
		[ThreadStatic]
		internal static Inventory? CountingInventory;

		[ThreadStatic]
		internal static List<Inventory>? CountingStorage;

		private static ItemData? SelectedItem(InventoryGui gui)
		{
			object value = Traverse.Create((object)gui).Field("m_selectedRecipe").GetValue();
			if (value != null)
			{
				return Traverse.Create(value).Property<ItemData>("ItemData", (object[])null).Value;
			}
			return null;
		}

		internal static bool HaveRequirements(Player player, Recipe recipe, bool discover, int quality, int amount)
		{
			InventoryGui instance = InventoryGui.instance;
			if (player.HaveRequirements(recipe, discover, quality, amount))
			{
				return true;
			}
			if (discover || (Object)(object)player != (Object)(object)Player.m_localPlayer || (Object)(object)instance == (Object)null || instance.InCraftTab() || SelectedItem(instance) == null || (Object)(object)CraftManagerService.GetSelectedRecipe(instance) != (Object)(object)recipe)
			{
				return false;
			}
			Inventory countingInventory = CountingInventory;
			List<Inventory> countingStorage = CountingStorage;
			try
			{
				CountingInventory = ((Humanoid)player).GetInventory();
				CountingStorage = (from container in CraftManagerService.FindUsableContainers(player)
					select container.GetInventory() into inventory
					where inventory != null
					select inventory).ToList();
				return player.HaveRequirements(recipe, discover, quality, amount);
			}
			finally
			{
				CountingInventory = countingInventory;
				CountingStorage = countingStorage;
			}
		}

		internal static bool PrepareUpgrade(InventoryGui gui)
		{
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			ItemData val = SelectedItem(gui);
			Recipe selectedRecipe = CraftManagerService.GetSelectedRecipe(gui);
			if (gui.InCraftTab() || val == null || (Object)(object)localPlayer == (Object)null || (Object)(object)selectedRecipe == (Object)null)
			{
				return true;
			}
			if (Traverse.Create((object)gui).Field<float>("m_craftTimer").Value >= 0f)
			{
				return false;
			}
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			int num = val.m_quality + 1;
			CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation();
			bool flag = (Object)(object)currentCraftingStation != (Object)null && currentCraftingStation.m_upgrader;
			if (!inventory.ContainsItem(val) || (!flag && num > selectedRecipe.m_item.m_itemData.m_shared.m_maxQuality))
			{
				return false;
			}
			if (localPlayer.NoCostCheat() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)25) || localPlayer.HaveRequirements(selectedRecipe, false, num, 1))
			{
				return true;
			}
			if (!HaveRequirements(localPlayer, selectedRecipe, discover: false, num, 1))
			{
				return false;
			}
			List<Container> source = CraftManagerService.FindUsableContainers(localPlayer);
			List<(Inventory, ItemData, int)> list = new List<(Inventory, ItemData, int)>();
			Requirement[] resources = selectedRecipe.m_resources;
			foreach (Requirement val2 in resources)
			{
				if ((Object)(object)val2.m_resItem == (Object)null || val2.m_upgraderResource != flag)
				{
					continue;
				}
				string name = val2.m_resItem.m_itemData.m_shared.m_name;
				int amount = val2.GetAmount(num);
				bool flag2 = false;
				foreach (int resourceQuality in from num4 in Enumerable.Range(1, val2.m_resItem.m_itemData.m_shared.m_maxQuality)
					orderby inventory.CountItems(name, num4, true) descending
					select num4)
				{
					int num2 = Math.Max(0, amount - inventory.CountItems(name, resourceQuality, true));
					List<(Inventory, ItemData)> list2 = (from container in source
						select container.GetInventory() into val6
						where val6 != null
						select val6).SelectMany((Inventory val6) => from stack in val6.GetAllItems()
						where stack.m_shared.m_name == name && stack.m_quality == resourceQuality && stack.m_worldLevel >= Game.m_worldLevel
						select (source: val6, item: stack)).ToList();
					if (list2.Sum<(Inventory, ItemData)>(((Inventory source, ItemData item) candidate) => candidate.item.m_stack) < num2)
					{
						continue;
					}
					foreach (var item in list2)
					{
						int num3 = Math.Min(num2, item.Item2.m_stack);
						if (num3 > 0)
						{
							list.Add((item.Item1, item.Item2, num3));
						}
						num2 -= num3;
						if (num2 == 0)
						{
							break;
						}
					}
					flag2 = true;
					break;
				}
				if (selectedRecipe.m_requireOnlyOneIngredient && flag2)
				{
					break;
				}
				if (!flag2 && !selectedRecipe.m_requireOnlyOneIngredient)
				{
					return false;
				}
			}
			Inventory val3 = new Inventory("CraftManager upgrade capacity", (Sprite)null, inventory.GetWidth(), inventory.GetHeight());
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				val3.GetAllItems().Add(allItem.Clone());
			}
			foreach (var item2 in list)
			{
				ItemData val4 = item2.Item2.Clone();
				val4.m_stack = item2.Item3;
				if (!val3.CanAddItem(val4, val4.m_stack) || !val3.AddItem(val4))
				{
					((Character)localPlayer).Message((MessageType)1, "$inventory_full", 0, (Sprite)null, false);
					return false;
				}
			}
			foreach (var item3 in list)
			{
				ItemData val5 = item3.Item2.Clone();
				val5.m_stack = item3.Item3;
				if (!inventory.CanAddItem(val5, val5.m_stack) || !item3.Item1.RemoveItem(item3.Item2, item3.Item3))
				{
					return false;
				}
				if (!inventory.AddItem(val5))
				{
					item3.Item1.AddItem(val5);
					return false;
				}
			}
			CraftManagerPlugin.Log.LogInfo((object)$"Upgrade '{val.m_shared.m_name}' to quality {num}: pulled {list.Sum<(Inventory, ItemData, int)>(((Inventory source, ItemData item, int amount) transfer) => transfer.amount)} material(s).");
			return localPlayer.HaveRequirements(selectedRecipe, false, num, 1);
		}
	}
}