Decompiled source of SmarterContainers v1.7.0

plugins/SmartContainers.dll

Decompiled 6 months ago
using System;
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 BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("SmartContainers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SmartContainers")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6b695573-f20c-49d7-99c3-26f3bd0c12c1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace SmartContainers;

internal sealed class ConfigurationManagerAttributes
{
	public bool? ShowRangeAsPercent;

	public Action<ConfigEntryBase> CustomDrawer;

	public bool? Browsable;

	public string Category;

	public object DefaultValue;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;

	public bool? ReadOnly;

	public bool? IsAdvanced;

	public Func<object, string> ObjToStr;

	public Func<string, object> StrToObj;
}
public static class ContainersTracker
{
	public static ICollection<Container> containerList = new List<Container>();

	public static bool isRearrangingItem = false;

	public static bool teleportingInProgress = false;

	public static List<Container> GetNearbyContainers(Vector3 center, bool all = false)
	{
		//IL_0066: 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)
		List<Container> list = new List<Container>();
		foreach (Container container in containerList)
		{
			int num = (all ? (Mod.range.Value * 2) : Mod.range.Value);
			if ((Object)(object)container != (Object)null && (Object)(object)((Component)container).transform != (Object)null && container.GetInventory() != null && (Object)(object)((Component)container).GetComponentInParent<Piece>() != (Object)null)
			{
				float num2 = Vector3.Distance(center, ((Component)container).transform.position);
				if ((num <= 0 || num2 < (float)num) && container.CheckAccess(Player.m_localPlayer.GetPlayerID()))
				{
					list.Add(container);
				}
			}
		}
		return list;
	}

	public static void Init()
	{
		Container[] array = Object.FindObjectsOfType<Container>();
		Mod.log.LogDebug((object)$"tracking {array.Length} discovered containers.");
		Container[] array2 = array;
		foreach (Container val in array2)
		{
			if (!((Object)val).name.StartsWith("Treasure") && val.GetInventory() != null && val.m_nview.IsValid() && val.m_nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0L)
			{
				containerList.Add(val);
			}
		}
	}

	public static void CleanupContainersList()
	{
		Mod.log.LogDebug((object)$"cleanup containerList. size before: {containerList.Count}");
		foreach (Container item in containerList.ToList())
		{
			if (!((Object)(object)item != (Object)null) || !((Object)(object)((Component)item).transform != (Object)null) || item.GetInventory() == null)
			{
				containerList.Remove(item);
			}
		}
		Mod.log.LogDebug((object)$"cleanup containerList. size after: {containerList.Count}");
	}
}
[HarmonyPatch(typeof(Container), "Awake")]
internal static class Container_Awake_Patch
{
	private static void Postfix(Container __instance)
	{
		if (Mod.modEnabled.Value && !((Object)__instance).name.StartsWith("Treasure") && __instance.GetInventory() != null && __instance.m_nview.IsValid() && (__instance.m_nview.GetZDO().GetLong(StringExtensionMethods.GetStableHashCode("creator"), 0L) != 0L || __instance.m_nview.GetZDO().GetOwner() != 0L))
		{
			ContainersTracker.containerList.Add(__instance);
		}
	}
}
[HarmonyPatch(typeof(Container), "OnDestroyed")]
internal static class Container_OnDestroyed_Patch
{
	private static void Prefix(Container __instance)
	{
		if (Mod.modEnabled.Value)
		{
			ContainersTracker.containerList.Remove(__instance);
		}
	}
}
[HarmonyPatch(typeof(Inventory), "StackAll")]
internal static class Container_OnStackAll_Patch
{
	private static void Postfix(Inventory __instance, Inventory fromInventory, bool message)
	{
		if (Mod.unloadAllEnabled.Value && Mod.unloadAllInsteadStackBtn.Value)
		{
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_playerGrid == (Object)null) && !((Object)(object)instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
			{
				UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory());
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdateTeleport")]
public static class PlayerUpdateTeleport_Patch_Cleanup_Containers
{
	public static void Prefix(float dt)
	{
		if (Mod.modEnabled.Value)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && localPlayer.m_teleporting && !ContainersTracker.teleportingInProgress)
			{
				ContainersTracker.teleportingInProgress = true;
			}
		}
	}
}
[HarmonyPatch(typeof(Player), "UpdateTeleport")]
public static class PlayerUpdateTeleport_Postfix
{
	public static void Postfix(float dt)
	{
		if (Mod.modEnabled.Value)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && ContainersTracker.teleportingInProgress && !localPlayer.m_teleporting)
			{
				ContainersTracker.CleanupContainersList();
				ContainersTracker.teleportingInProgress = false;
			}
		}
	}
}
[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
public static class Inventory_Patch
{
	public static void Postfix(Inventory __instance, ItemData item, ref bool __result)
	{
		//IL_00a5: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cd: 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_017d: Unknown result type (might be due to invalid IL or missing references)
		if (!Mod.modEnabled.Value || __instance == null || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsTeleporting() || ((object)__instance).Equals((object?)((Humanoid)Player.m_localPlayer).GetInventory()) || !((Humanoid)Player.m_localPlayer).GetInventory().ContainsItem(item) || (Mod.onlyStackableItems.Value && item.m_shared.m_maxStackSize == 1) || ContainersTracker.isRearrangingItem)
		{
			return;
		}
		if (Input.GetKey((KeyCode)108))
		{
			Console.instance.Print("SmartContainers tracked item [" + item.m_shared.m_name + "]");
		}
		KeyboardShortcut value = Mod.keyModifier.Value;
		if (!((KeyboardShortcut)(ref value)).IsPressed())
		{
			value = Mod.groupingKeyModifier.Value;
			if (!((KeyboardShortcut)(ref value)).IsPressed() && (!Mod.gamepadKey2.Value.MainPressed() || !ZInput.GetButton(Mod.gamepadKey1.Value)))
			{
				return;
			}
		}
		if ((Object)(object)InventoryGui.instance == (Object)null || !InventoryGui.instance.IsContainerOpen())
		{
			return;
		}
		ContainersTracker.isRearrangingItem = true;
		if (!__result)
		{
			if (TryAddToNearBy(item))
			{
				__result = true;
				Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint());
			}
		}
		else if (__instance.CountItems(item.m_shared.m_name, -1, true) == item.m_stack && TryAddToNearBy(item))
		{
			__instance.RemoveItem(item);
			Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint());
		}
		ContainersTracker.isRearrangingItem = false;
	}

	public static bool TryAddToNearBy(ItemData item, bool allowCurrent = false, bool forceGrouping = false)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0403: Unknown result type (might be due to invalid IL or missing references)
		//IL_0408: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			Container openedContainer = InventoryGui.instance.m_currentContainer;
			if (Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened() && ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position, all: true).Any((Container c) => ((object)openedContainer).GetHashCode() != ((object)c).GetHashCode() && c.m_nview.GetZDO().GetInt("InUse", 0) == 1))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "Cant distribute items: other Player is using containers nearby.", 0, (Sprite)null);
				return false;
			}
			List<Container> list = (from c in ContainersTracker.GetNearbyContainers(((Component)Player.m_localPlayer).transform.position)
				where ((object)openedContainer).GetHashCode() == ((object)c).GetHashCode() || (Mod.concurrencyWorkaround.Value.Ignore() && ((object)openedContainer).GetHashCode() != ((object)c).GetHashCode()) || ((Mod.concurrencyWorkaround.Value.SkipOpenedOthers() || Mod.concurrencyWorkaround.Value.BlockIfAnyOtherOpened()) && c.m_nview.GetZDO().GetInt("InUse", 0) == 0)
				select c).ToList();
			foreach (Container item2 in list)
			{
				if (item2.GetInventory().CanAddItem(item, -1) && (allowCurrent || ((object)openedContainer).GetHashCode() != ((object)item2).GetHashCode()) && item2.GetInventory().HaveItem(item.m_shared.m_name, true))
				{
					Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has same item stack");
					return AddItemToContainer(item, item2, allowCurrent);
				}
			}
			KeyboardShortcut value;
			if (Mod.groupingEnabled.Value)
			{
				if (!forceGrouping)
				{
					value = Mod.groupingKeyModifier.Value;
					if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive())
					{
						goto IL_03ef;
					}
				}
				List<Tuple<string, Container>> list2 = new List<Tuple<string, Container>>();
				foreach (Container item3 in list)
				{
					if (item3.GetInventory().CanAddItem(item, -1))
					{
						string text = ItemGroups.FindMatchingUserGroup(item3, item);
						if (text != null)
						{
							list2.Add(Tuple.Create<string, Container>(text, item3));
						}
					}
				}
				if (list2.Any())
				{
					Tuple<string, Container> tuple = list2.OrderByDescending((Tuple<string, Container> t) => t.Item1).First();
					if (list2.Count > 1)
					{
						Mod.log.LogWarning((object)("Ambiguous item-groups [" + string.Join(",", list2) + "] found for " + ((Object)item.m_dropPrefab).name + " item. Using " + tuple.Item1));
					}
					Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item from group " + tuple.Item1 + " : [" + string.Join(",", ItemGroups.Groups[tuple.Item1]) + "]");
					return AddItemToContainer(item, tuple.Item2, allowCurrent);
				}
				foreach (Container item4 in list)
				{
					if (item4.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSame_SystemGroupItems(item4, item))
					{
						return AddItemToContainer(item, item4, allowCurrent);
					}
				}
				foreach (Container item5 in list)
				{
					if (item5.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSame_NamePatternItems(item5, item))
					{
						return AddItemToContainer(item, item5, allowCurrent);
					}
				}
				if (Mod.itemTypeGroupsEnabled.Value)
				{
					foreach (Container item6 in list)
					{
						if (item6.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSameItemType(item6, item))
						{
							return AddItemToContainer(item, item6, allowCurrent);
						}
					}
				}
				goto IL_03ef;
			}
			goto IL_046b;
			IL_03ef:
			if (Mod.fuzzyGroupingEnabled.Value)
			{
				if (!forceGrouping)
				{
					value = Mod.groupingKeyModifier.Value;
					if (!((KeyboardShortcut)(ref value)).IsPressed() && !ZInput.IsGamepadActive())
					{
						goto IL_046b;
					}
				}
				foreach (Container item7 in list)
				{
					if (item7.GetInventory().CanAddItem(item, -1) && ItemGroups.ContainerHasSimilarGroupItems(item7, item))
					{
						return AddItemToContainer(item, item7, allowCurrent);
					}
				}
			}
			goto IL_046b;
			IL_046b:
			return false;
		}
		catch (Exception ex)
		{
			Mod.log.LogError((object)("Failed to rearrange container items: " + ex));
		}
		return false;
	}

	private static bool AddItemToContainer(ItemData item, Container targetContainer, bool allowCurrent = false)
	{
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		Container currentContainer = InventoryGui.instance.m_currentContainer;
		if (allowCurrent || ((object)currentContainer).GetHashCode() != ((object)targetContainer).GetHashCode())
		{
			bool num = targetContainer.GetInventory().AddItem(item);
			if (num)
			{
				targetContainer.Save();
				targetContainer.GetInventory().Changed();
				if (Mod.hudMessageEnabled.Value && !((object)InventoryGui.instance.m_currentContainer).Equals((object?)targetContainer))
				{
					MessageHud.instance.QueueUnlockMsg(item.GetIcon(), item.m_shared.m_name, Mod.hudMessageText.Value);
				}
				Mod.PlayEffect(Mod.effectFeedbackEnabled.Value, "vfx_Potion_health_medium", ((Component)targetContainer).transform.position);
			}
			return num;
		}
		return false;
	}
}
public static class GuiFactory
{
	public static void CreateMrgDialog(out GameObject dialogObj, string dlgUid, string label1, string label2, string label3, UnityAction onFirst, UnityAction onSecond, UnityAction onThird)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: 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_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: 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_020e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0213: Unknown result type (might be due to invalid IL or missing references)
		//IL_0223: Unknown result type (might be due to invalid IL or missing references)
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Unknown result type (might be due to invalid IL or missing references)
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Expected O, but got Unknown
		//IL_0278: Unknown result type (might be due to invalid IL or missing references)
		//IL_028c: Expected O, but got Unknown
		//IL_028e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Expected O, but got Unknown
		//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_0307: Unknown result type (might be due to invalid IL or missing references)
		//IL_0318: Unknown result type (might be due to invalid IL or missing references)
		//IL_031d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0327: Unknown result type (might be due to invalid IL or missing references)
		//IL_0338: Unknown result type (might be due to invalid IL or missing references)
		//IL_033d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_0358: Unknown result type (might be due to invalid IL or missing references)
		//IL_035d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_0373: Unknown result type (might be due to invalid IL or missing references)
		//IL_0389: Unknown result type (might be due to invalid IL or missing references)
		//IL_039e: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_040c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0435: Unknown result type (might be due to invalid IL or missing references)
		//IL_0463: Unknown result type (might be due to invalid IL or missing references)
		//IL_0472: Unknown result type (might be due to invalid IL or missing references)
		//IL_04a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0504: Unknown result type (might be due to invalid IL or missing references)
		//IL_0527: Unknown result type (might be due to invalid IL or missing references)
		//IL_0531: Expected O, but got Unknown
		//IL_0533: Unknown result type (might be due to invalid IL or missing references)
		//IL_0547: Expected O, but got Unknown
		//IL_0576: Unknown result type (might be due to invalid IL or missing references)
		//IL_0585: Unknown result type (might be due to invalid IL or missing references)
		//IL_0590: Unknown result type (might be due to invalid IL or missing references)
		//IL_05a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_05cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_05da: Unknown result type (might be due to invalid IL or missing references)
		Transform val = ((Component)InventoryGui.instance).gameObject.transform.Find("root/SplitDialog");
		Transform val2 = Object.Instantiate<Transform>(val, val.parent);
		((Object)val2).name = dlgUid;
		Transform winWrap = val2.Find("win_bkg");
		((RectTransform)winWrap).SetSizeWithCurrentAnchors((Axis)0, 500f);
		dialogObj = ((Component)val2).gameObject;
		Object.Destroy((Object)(object)((Component)winWrap.Find("Icon_bkg")).gameObject);
		Object.Destroy((Object)(object)((Component)winWrap.Find("Slider")).gameObject);
		Object.Destroy((Object)(object)((Component)winWrap.Find("Text")).gameObject);
		Object.Destroy((Object)(object)((Component)winWrap.Find("amount")).gameObject);
		((Component)winWrap.Find("Button_cancel")).gameObject.AddComponent(typeof(UIGamePad));
		((Component)winWrap.Find("Button_ok")).gameObject.AddComponent(typeof(UIGamePad));
		Transform val3 = winWrap.Find("Button_cancel");
		Transform val4 = winWrap.Find("Button_ok");
		Transform val5 = Object.Instantiate<Transform>(val4, ((Component)winWrap).transform);
		((Object)val5).name = "Button_3";
		((TMP_Text)((Component)val3.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label1;
		((TMP_Text)((Component)val4.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label2;
		((TMP_Text)((Component)val5.Find("Text")).GetComponent<TextMeshProUGUI>()).text = label3;
		RectTransform val6 = (RectTransform)((Component)val3).transform;
		val6.pivot += new Vector2(0.5f, 0.7f);
		RectTransform val7 = (RectTransform)((Component)val4).transform;
		val7.pivot += new Vector2(0.57f, 0.7f);
		RectTransform val8 = (RectTransform)((Component)val5).transform;
		val8.pivot += new Vector2(-0.48f, 0.7f);
		((RectTransform)((Component)val3).transform).SetSizeWithCurrentAnchors((Axis)1, 40f);
		((RectTransform)((Component)val4).transform).SetSizeWithCurrentAnchors((Axis)1, 40f);
		((RectTransform)((Component)val5).transform).SetSizeWithCurrentAnchors((Axis)1, 40f);
		InitJoyKey((Transform)(RectTransform)val3, "JoyTabLeft", "(LB)");
		InitJoyKey((Transform)(RectTransform)val4, "JoyTabRight", "(RB)");
		InitJoyKey((Transform)(RectTransform)val5, "", "");
		Transform obj = Object.Instantiate<Transform>(((Component)InventoryGui.instance).gameObject.transform.Find("root/Texts/Texts_frame/TextArea"), winWrap);
		((Object)obj).name = "TextArea";
		((Component)obj).gameObject.SetActive(true);
		((Graphic)((Component)obj).GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.4f);
		RectTransform val9 = (RectTransform)obj;
		((Transform)val9).position = ((Transform)(RectTransform)((Component)val.Find("win_bkg/bkg")).transform).position;
		((Transform)val9).localScale = ((Transform)(RectTransform)((Component)val.Find("win_bkg/bkg")).transform).localScale;
		val9.sizeDelta = ((RectTransform)((Component)val.Find("win_bkg/bkg")).transform).sizeDelta;
		val9.SetSizeWithCurrentAnchors((Axis)1, 190f);
		val9.SetSizeWithCurrentAnchors((Axis)0, 515f);
		val9.pivot = new Vector2(0.51f, 0.33f);
		((RectTransform)obj.Find("ScrollArea/Content/Name")).SetSizeWithCurrentAnchors((Axis)0, 515f);
		((RectTransform)obj.Find("ScrollArea/Content/Description")).SetSizeWithCurrentAnchors((Axis)0, 515f);
		TextMeshProUGUI component = ((Component)obj.Find("ScrollArea/Content/Name")).GetComponent<TextMeshProUGUI>();
		TextMeshProUGUI component2 = ((Component)obj.Find("ScrollArea/Content/Description")).GetComponent<TextMeshProUGUI>();
		((TMP_Text)component).fontSize = 18f;
		((Graphic)component).color = new Color(0.79f, 0.75f, 0.28f, 1f);
		((TMP_Text)component2).fontSize = 18f;
		((Graphic)component2).color = new Color(0.8f, 0.8f, 0.8f, 1f);
		Transform val10 = CreateButton("Selector", "--select--", winWrap.Find("TextArea"), new Vector2(380f, 24f), new Vector2(-0.23f, 11.4f));
		GameObject val11 = Object.Instantiate<GameObject>(Find("RecipeList"), winWrap);
		((Object)val11).name = "SelectorDlg";
		((RectTransform)val11.transform).pivot = new Vector2(-0.55f, 1.7f);
		Transform val12 = val11.transform.Find("Recipes/ListRoot");
		for (int i = 0; i < val12.childCount; i++)
		{
			Object.Destroy((Object)(object)((Component)val12.GetChild(i)).gameObject);
		}
		((RectTransform)val11.transform).SetSizeWithCurrentAnchors((Axis)1, 150f);
		((UnityEvent)((Component)val10).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
		{
			GameObject gameObject = ((Component)winWrap.Find("SelectorDlg")).gameObject;
			gameObject.SetActive(!gameObject.activeSelf);
		});
		InitJoyKey((Transform)(RectTransform)val10, "", "");
		Transform obj2 = Object.Instantiate<Transform>(((Component)InventoryGui.instance.m_takeAllButton).transform.Find("Text"), winWrap.Find("TextArea"));
		((RectTransform)obj2).pivot = new Vector2(-0.05f, -0.13f);
		((RectTransform)obj2).SetSizeWithCurrentAnchors((Axis)1, 24f);
		((RectTransform)obj2).SetSizeWithCurrentAnchors((Axis)0, 150f);
		((TMP_Text)((Component)obj2).GetComponent<TextMeshProUGUI>()).text = "Target group:";
		((RectTransform)((Component)winWrap).transform).pivot = new Vector2(-0.7f, 1f);
		((UnityEvent)((Component)val3).GetComponent<Button>().onClick).AddListener(onFirst);
		((UnityEvent)((Component)val4).GetComponent<Button>().onClick).AddListener(onSecond);
		((UnityEvent)((Component)val5).GetComponent<Button>().onClick).AddListener(onThird);
	}

	public static Transform AddContainerGuiButton(string btnObjName, string text, Vector2 size, Vector2 pos)
	{
		//IL_0016: 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)
		return CreateButton(btnObjName, text, ((Component)InventoryGui.instance.m_takeAllButton).transform.parent, size, pos);
	}

	public static Transform CreateButton(string btnObjName, string text, Transform parent, Vector2 size, Vector2 pos)
	{
		//IL_0007: 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_0033: 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_0040: 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_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: 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)
		//IL_0064: 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_0071: 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_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Expected O, but got Unknown
		_ = (RectTransform)parent.Find(btnObjName);
		Transform obj = Object.Instantiate<Transform>(((Component)InventoryGui.instance.m_takeAllButton).transform, parent);
		((Object)obj).name = btnObjName;
		RectTransform val = (RectTransform)((Component)obj).transform;
		val.SetSizeWithCurrentAnchors((Axis)0, size.x);
		val.SetSizeWithCurrentAnchors((Axis)1, size.y);
		RectTransform val2 = (RectTransform)((Component)val).transform.Find("Text");
		val2.SetSizeWithCurrentAnchors((Axis)0, size.x);
		val2.SetSizeWithCurrentAnchors((Axis)1, size.y);
		((TMP_Text)((Component)val2).GetComponent<TextMeshProUGUI>()).text = text;
		val.pivot = pos;
		return (Transform)val;
	}

	public static void InitJoyKey(Transform btnComponent, string joyKeyCode, string tooltip)
	{
		//IL_0049: 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_006e: 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)
		UIGamePad component = ((Component)btnComponent).GetComponent<UIGamePad>();
		Transform val = Object.Instantiate<Transform>(((Component)btnComponent).transform.Find("Text"), ((Component)component).transform);
		((TMP_Text)((Component)val).GetComponent<TextMeshProUGUI>()).text = tooltip;
		((Graphic)((Component)val).GetComponent<TextMeshProUGUI>()).color = new Color(0.8f, 0.8f, 0.8f, 1f);
		Transform transform = ((Component)val).transform;
		transform.position += new Vector3(0f, 13f, 0f);
		if ((Object)(object)component.m_hint != (Object)null)
		{
			Object.Destroy((Object)(object)component.m_hint);
		}
		component.m_hint = ((Component)val).gameObject;
		component.m_zinputKey = joyKeyCode;
		((Behaviour)((Component)val).GetComponent<TextMeshProUGUI>()).enabled = ZInput.IsGamepadActive();
	}

	public static void FillResList(RectTransform parent, ICollection<string> names, ICollection<Object> m_resObjects, Action<string> cb)
	{
		//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Expected O, but got Unknown
		//IL_0113: 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)
		foreach (Object m_resObject in m_resObjects)
		{
			Object.Destroy(m_resObject);
		}
		m_resObjects.Clear();
		float num = 0f;
		GameObject val = Find("RecipeList/Recipes/RecipeElement");
		foreach (string groupName in names)
		{
			GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)parent).transform);
			Object.Destroy((Object)(object)((Component)val2.transform.Find("icon")).gameObject);
			Object.Destroy((Object)(object)((Component)val2.transform.Find("Durability")).gameObject);
			Object.Destroy((Object)(object)((Component)val2.transform.Find("QualityLevel")).gameObject);
			val2.SetActive(true);
			((UnityEvent)val2.GetComponentInChildren<Button>().onClick).AddListener((UnityAction)delegate
			{
				cb(groupName);
			});
			Transform transform = val2.transform;
			((RectTransform)((transform is RectTransform) ? transform : null)).anchoredPosition = new Vector2(0f, num * -20f);
			((TMP_Text)val2.GetComponentInChildren<TextMeshProUGUI>()).text = groupName;
			m_resObjects.Add((Object)(object)val2);
			num += 1f;
		}
		Rect rect = parent.rect;
		parent.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(((Rect)(ref rect)).height, num * 20f));
	}

	private static GameObject Find(string name)
	{
		GameObject val = GameObject.Find("_GameMain/LoadingGUI/PixelFix/IngameGui/Inventory_screen/root/Crafting/" + name);
		if ((Object)(object)val == (Object)null)
		{
			Mod.log.LogWarning((object)("Failed to locate '" + name + "' GameObject - fallback to IngameGui(Clone) lookup.."));
			val = ((Component)GameObject.Find("IngameGui").transform.Find("Inventory_screen/root/Crafting/" + name)).gameObject;
		}
		return val;
	}
}
[HarmonyPatch(typeof(InventoryGui), "Show")]
public static class Gui_Patch
{
	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static Func<Tuple<string, List<string>>, string> <>9__8_3;

		public static UnityAction <>9__8_0;

		public static Func<Tuple<string, List<string>>, string> <>9__8_4;

		public static UnityAction <>9__8_1;

		public static Func<Tuple<string, List<string>>, string> <>9__8_5;

		public static UnityAction <>9__8_2;

		public static Func<Tuple<string, List<string>>, string> <>9__10_0;

		public static Func<Tuple<string, List<string>>, IEnumerable<string>> <>9__10_1;

		public static Func<ItemData, bool> <>9__10_5;

		public static Func<ItemData, string> <>9__10_6;

		public static Func<Tuple<string, List<string>>, string> <>9__10_8;

		public static Func<Tuple<string, List<string>>, string> <>9__10_3;

		internal void <InitButtons>b__8_0()
		{
			if (containersUniqueItems != null && intersectedGroups != null)
			{
				ItemGroupUtils.ExtendGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
			}
			groupsDialogObj.gameObject.SetActive(false);
		}

		internal string <InitButtons>b__8_3(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}

		internal void <InitButtons>b__8_1()
		{
			if (containersUniqueItems != null)
			{
				ItemGroupUtils.ExtendAndMerge(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
			}
			groupsDialogObj.gameObject.SetActive(false);
		}

		internal string <InitButtons>b__8_4(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}

		internal void <InitButtons>b__8_2()
		{
			if (containersUniqueItems != null && intersectedGroups != null)
			{
				ItemGroupUtils.MergeAllToSingleGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
			}
			groupsDialogObj.gameObject.SetActive(false);
		}

		internal string <InitButtons>b__8_5(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}

		internal string <InitMergePromptDlg>b__10_0(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}

		internal IEnumerable<string> <InitMergePromptDlg>b__10_1(Tuple<string, List<string>> _)
		{
			return _.Item2;
		}

		internal bool <InitMergePromptDlg>b__10_5(ItemData i)
		{
			return intersectedGroups[0].Item2.Contains(i.SCName());
		}

		internal string <InitMergePromptDlg>b__10_6(ItemData _)
		{
			return Localization.instance.Localize(_.m_shared.m_name);
		}

		internal string <InitMergePromptDlg>b__10_8(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}

		internal string <InitMergePromptDlg>b__10_3(Tuple<string, List<string>> _)
		{
			return _.Item1;
		}
	}

	public static bool initialized = false;

	private static Transform createGroupButton;

	private static Transform storeAllButton;

	public static GameObject groupsDialogObj;

	private static readonly ICollection<Object> groupSelectorItems = new List<Object>();

	private static List<Tuple<string, List<string>>> intersectedGroups;

	private static List<string> containersUniqueItems;

	private static void Postfix(InventoryGui __instance)
	{
		if (Mod.modEnabled.Value && Mod.groupingEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)Player.m_localPlayer == (Object)null) && !initialized && __instance.IsContainerOpen())
		{
			InitButtons(__instance);
		}
	}

	private static void InitButtons(InventoryGui __instance)
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_00a5: 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_00b0: Expected O, but got Unknown
		//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_00cf: Expected O, but got Unknown
		if (!Mod.modEnabled.Value)
		{
			return;
		}
		try
		{
			if ((Mod.groupingEnabled.Value || Mod.unloadAllEnabled.Value) && Mod.createGroupBtnEnabled.Value)
			{
				AddCreateGroupBtn(__instance);
				if (Mod.groupingEnabled.Value && Mod.mergePromptEnabled.Value)
				{
					object obj = <>c.<>9__8_0;
					if (obj == null)
					{
						UnityAction val = delegate
						{
							if (containersUniqueItems != null && intersectedGroups != null)
							{
								ItemGroupUtils.ExtendGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
							}
							groupsDialogObj.gameObject.SetActive(false);
						};
						<>c.<>9__8_0 = val;
						obj = (object)val;
					}
					object obj2 = <>c.<>9__8_1;
					if (obj2 == null)
					{
						UnityAction val2 = delegate
						{
							if (containersUniqueItems != null)
							{
								ItemGroupUtils.ExtendAndMerge(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
							}
							groupsDialogObj.gameObject.SetActive(false);
						};
						<>c.<>9__8_1 = val2;
						obj2 = (object)val2;
					}
					object obj3 = <>c.<>9__8_2;
					if (obj3 == null)
					{
						UnityAction val3 = delegate
						{
							if (containersUniqueItems != null && intersectedGroups != null)
							{
								ItemGroupUtils.MergeAllToSingleGroup(SelectedTargetGroupId(), intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList(), containersUniqueItems);
							}
							groupsDialogObj.gameObject.SetActive(false);
						};
						<>c.<>9__8_2 = val3;
						obj3 = (object)val3;
					}
					GuiFactory.CreateMrgDialog(out groupsDialogObj, "mrgToGroupDialog", "Extend", "Extend&Merge", "Merge All", (UnityAction)obj, (UnityAction)obj2, (UnityAction)obj3);
				}
			}
			if (Mod.unloadAllEnabled.Value && !Mod.unloadAllInsteadStackBtn.Value)
			{
				AddStoreAllBtn(__instance);
			}
			initialized = true;
		}
		catch (Exception ex)
		{
			Mod.log.LogError((object)("Failed to properly patch GUI with additional buttons: " + ex));
			Clean();
		}
		finally
		{
			Mod.log.LogInfo((object)"Initialized UI extensions.");
		}
	}

	private static void AddCreateGroupBtn(InventoryGui __instance)
	{
		//IL_0021: 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)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		createGroupButton = GuiFactory.AddContainerGuiButton("createGroupBtn", "+æ+", new Vector2(45f, 30f), Mod.createGroupBtnPos.Value);
		GuiFactory.InitJoyKey(createGroupButton, "JoyMap", "(Гг)");
		((UnityEvent)((Component)createGroupButton).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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)
			if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
			{
				Inventory inventory = __instance.m_containerGrid.GetInventory();
				KeyboardShortcut value;
				if (Mod.unloadAllEnabled.Value)
				{
					value = Mod.unloadAllItemsGroupKeyModifier.Value;
					if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyRTrigger"))
					{
						UnloadItems.AddToUnloadAllItemsFilter(inventory);
						return;
					}
				}
				if (Mod.unloadAllEnabled.Value)
				{
					value = Mod.unloadAllSkipItemsGroupKeyModifier.Value;
					if (((KeyboardShortcut)(ref value)).IsPressed() || ZInput.GetButton("JoyLTrigger"))
					{
						UnloadItems.AddToUnloadAllItemsSkipList(inventory);
						return;
					}
				}
				if (Mod.groupingEnabled.Value)
				{
					containersUniqueItems = ItemGroupUtils.ExtractUniqueItemNames(inventory);
					if (containersUniqueItems.Count >= 2)
					{
						if (Mod.mergePromptEnabled.Value)
						{
							InitMergePromptDlg(inventory);
						}
						else
						{
							ItemGroupUtils.RegisterNewGroup(inventory);
						}
					}
				}
			}
		});
	}

	private static void InitMergePromptDlg(Inventory inventory)
	{
		//IL_0378: Unknown result type (might be due to invalid IL or missing references)
		//IL_0382: Expected O, but got Unknown
		//IL_0396: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ed: Expected O, but got Unknown
		intersectedGroups = ItemGroupUtils.FindIntersections(containersUniqueItems);
		if (!intersectedGroups.Any())
		{
			ItemGroupUtils.RegisterNewGroup(inventory);
			return;
		}
		List<string> second = intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).ToList();
		HashSet<string> intersectedItemNames = intersectedGroups.FlatMap((Tuple<string, List<string>> _) => _.Item2).ToHashSet();
		List<string> nonGroupedItems = containersUniqueItems.Filter((string _) => !intersectedItemNames.Contains(_)).ToList();
		TextMeshProUGUI component = ((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/ScrollArea/Content/Name")).GetComponent<TextMeshProUGUI>();
		TextMeshProUGUI component2 = ((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/ScrollArea/Content/Description")).GetComponent<TextMeshProUGUI>();
		if (intersectedGroups.Count == 1)
		{
			if (!nonGroupedItems.Any())
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "Group " + intersectedGroups[0].Item1 + " already contains these items", 0, (Sprite)null);
				return;
			}
			List<string> list = inventory.m_inventory.Filter((ItemData i) => intersectedGroups[0].Item2.Contains(i.SCName())).Map((ItemData _) => Localization.instance.Localize(_.m_shared.m_name)).Distinct()
				.ToList();
			((TMP_Text)component).text = string.Join(",", list.Take(3)) + " " + ((list.Count > 3) ? "and others " : "") + ((list.Count > 1) ? "are already members" : "is already a member") + $" of an existing group of {ItemGroups.Groups[intersectedGroups[0].Item1].Count} items. ";
		}
		else
		{
			((TMP_Text)component).text = $"Items from {intersectedGroups.Count} different groups are already presented in this container.";
		}
		((TMP_Text)component2).text = " Please review info bellow, select target-group & action.\n You can: \n • <color=#FFA13CB7>'Extend'</color>: add previously non-grouped items \n(colored in <color=green>green</color>) to a selected  target-group.\n";
		((TMP_Text)component2).text = ((TMP_Text)component2).text + " • <color=#FFA13CB7>'Extend & merge'</color>: add all items from this container to a selected target-group. All conflicting items (colored in <color=red>red</color>) would be removed from their current groups.\n";
		((TMP_Text)component2).text = ((TMP_Text)component2).text + " • <color=#FFA13CB7>'Merge all'</color>: (Not recommended) move all items (from this container) & all conflicting group items to a target group.All members of all listed bellow groups will be moved to a target group. \n<color=grey>(target-group could be a new or an existing group)</color>\n";
		List<string> list2 = UnloadItems.unloadAllGroupsList.Intersect(second).ToList();
		if (Mod.unloadAllEnabled.Value && list2.Any())
		{
			((TMP_Text)component2).text = ((TMP_Text)component2).text + " \n<color=orange> ! Please note that groups [" + string.Join(",", list2) + "] are used for 'Unloading' filtering. Changing them will affect it's behaviour.</color>\n";
		}
		((TMP_Text)component2).text = ((TMP_Text)component2).text + "\n Items in the container: " + GeneralExtensions.Join<string>(containersUniqueItems.Map((string itemName) => "<color=" + (nonGroupedItems.Contains(itemName) ? "green" : "red") + ">" + itemName + "</color>"), (Func<string, string>)null, ",") + ".\n";
		((TMP_Text)component2).text = ((TMP_Text)component2).text + "\n Detected groups: \n";
		((TMP_Text)component2).text = ((TMP_Text)component2).text + GeneralExtensions.Join<string>(intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).Map(delegate(string gKey)
		{
			IEnumerable<string> values = ItemGroups.Groups[gKey].Map((string _) => (!intersectedItemNames.Contains(_)) ? _ : ("<color=red>" + _ + "</color>"));
			return "<color=yellow>" + gKey + "</color>: [" + string.Join(", ", values) + "] \n";
		}), (Func<string, string>)null, "");
		RectTransform selectorBtn = (RectTransform)groupsDialogObj.transform.Find("win_bkg/TextArea/Selector");
		RectTransform val = (RectTransform)groupsDialogObj.transform.Find("win_bkg/SelectorDlg/Recipes/ListRoot");
		List<string> names = intersectedGroups.Map((Tuple<string, List<string>> _) => _.Item1).Prepend("--new Group--").ToList();
		GuiFactory.FillResList(val, names, groupSelectorItems, delegate(string selection)
		{
			((TMP_Text)((Component)selectorBtn).GetComponentInChildren<TextMeshProUGUI>()).text = selection;
			((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg")).gameObject.SetActive(false);
		});
		((TMP_Text)((Component)selectorBtn).GetComponentInChildren<TextMeshProUGUI>()).text = ((intersectedGroups.Count == 1) ? intersectedGroups[0].Item1 : "--new Group--");
		((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg/RecipeScroll")).GetComponent<Scrollbar>().value = 1f;
		((Component)groupsDialogObj.transform.Find("win_bkg/SelectorDlg")).gameObject.SetActive(false);
		groupsDialogObj.SetActive(true);
	}

	private static string SelectedTargetGroupId()
	{
		return ((TMP_Text)((Component)groupsDialogObj.transform.Find("win_bkg/TextArea/Selector")).GetComponentInChildren<TextMeshProUGUI>()).text;
	}

	private static void AddStoreAllBtn(InventoryGui __instance)
	{
		//IL_0021: 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)
		//IL_0064: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Expected O, but got Unknown
		storeAllButton = GuiFactory.AddContainerGuiButton("storeAllButton", "\\||/", new Vector2(45f, 36f), Mod.unloadAllBtnPos.Value);
		GuiFactory.InitJoyKey(storeAllButton, "JoyMenu", "(≡)");
		((UnityEvent)((Component)storeAllButton).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
		{
			if (!((Object)(object)__instance.m_playerGrid == (Object)null) && !((Object)(object)__instance.m_containerGrid == (Object)null) && !((Character)Player.m_localPlayer).IsTeleporting())
			{
				UnloadItems.UnloadAllItems(((Humanoid)Player.m_localPlayer).GetInventory());
			}
		});
	}

	public static void Init()
	{
		if ((Object)(object)InventoryGui.instance != (Object)null)
		{
			InitButtons(InventoryGui.instance);
		}
	}

	public static void Clean()
	{
		if ((Object)(object)createGroupButton != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)createGroupButton).gameObject);
		}
		if ((Object)(object)storeAllButton != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)storeAllButton).gameObject);
		}
		if ((Object)(object)groupsDialogObj != (Object)null)
		{
			Object.Destroy((Object)(object)groupsDialogObj);
		}
		initialized = false;
		Mod.log.LogInfo((object)"Cleaned up UI extensions.");
	}
}
[HarmonyPatch(typeof(Game), "Start")]
public static class Game_Start_Patch
{
	private static void Postfix(Game __instance)
	{
		Gui_Patch.Clean();
	}
}
[HarmonyPatch(typeof(InventoryGui), "Hide")]
public static class Gui_Hide_Patch
{
	private static void Postfix(InventoryGui __instance)
	{
		if (Gui_Patch.initialized)
		{
			GameObject groupsDialogObj = Gui_Patch.groupsDialogObj;
			if (groupsDialogObj != null)
			{
				groupsDialogObj.SetActive(false);
			}
		}
	}
}
public static class ItemGroups
{
	private static ICollection<string> prefixItemGroups = new HashSet<string>();

	private static ICollection<string> postfixItemGroups = new HashSet<string>();

	public static readonly IDictionary<string, ISet<string>> Groups = new Dictionary<string, ISet<string>>();

	public static void ParseConfig()
	{
		foreach (KeyValuePair<ConfigDefinition, string> item in Mod.ConfigOrphanedEntries().ToList())
		{
			if (item.Key.Section.Equals("ItemGroup"))
			{
				Mod.config.Bind<string>(item.Key.Section, item.Key.Key, item.Value.ToLower().Replace("_", ""), Mod.groupDescr("user-added items-group based on item-names list"));
			}
		}
		ConfigEntry<string> val = default(ConfigEntry<string>);
		if (Mod.config.TryGetEntry<string>("PrefixedItemGroups", "prefixes", ref val) && val.Value.Length > 0)
		{
			prefixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(val);
			Mod.log.LogInfo((object)string.Format("parsed PrefixedItemGroups : [{0}] ({1})", string.Join(",", prefixItemGroups), prefixItemGroups.Count));
		}
		ConfigEntry<string> val2 = default(ConfigEntry<string>);
		if (Mod.config.TryGetEntry<string>("PostfixedItemGroups", "posfixes", ref val2) && val2.Value.Length > 0)
		{
			postfixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(val2);
			Mod.log.LogInfo((object)string.Format("parsed PostfixedItemGroups: [{0}] ({1})", string.Join(",", postfixItemGroups), postfixItemGroups.Count));
		}
		ConfigEntry<string> val3 = default(ConfigEntry<string>);
		foreach (ConfigDefinition item2 in from itemKey in Mod.config.Keys
			where itemKey.Section.Equals("ItemGroup")
			select itemKey into _
			orderby _.Key
			select _)
		{
			if (Mod.config.TryGetEntry<string>(item2.Section, item2.Key, ref val3) && val3.Value.Length > 0)
			{
				ISet<string> set = ItemGroupUtils.ParseGroupConfigEntry(val3);
				Groups.Add(item2.Key, set);
				Mod.log.LogInfo((object)string.Format("parsed items group '{0}': [{1}] ({2})", item2.Key, string.Join(",", set), set.Count));
			}
		}
	}

	public static string FindMatchingUserGroup(Container container, ItemData item)
	{
		if (item.m_shared.m_name.Length < 7)
		{
			Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name));
			return null;
		}
		ICollection<string> collection = FindMatchingGroups(container, item.SCName(), item, Groups.Keys.Except(Mod.systemGroupKeys).ToList());
		if (collection.Count > 1)
		{
			Mod.log.LogWarning((object)("Ambiguous item-groups [" + string.Join(",", collection) + "] found for " + ((Object)item.m_dropPrefab).name + " item in single container."));
		}
		if (!collection.Any())
		{
			return null;
		}
		return collection.Max((string _) => _);
	}

	public static bool ContainerHasSame_SystemGroupItems(Container container, ItemData item)
	{
		if (item.m_shared.m_name.Length < 7)
		{
			Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name));
			return false;
		}
		return TestConfiguredGroups(container, item.SCName(), item, Mod.systemGroupKeys);
	}

	public static bool ContainerHasSame_NamePatternItems(Container container, ItemData item)
	{
		if (item.m_shared.m_name.Length < 7)
		{
			Mod.log.LogWarning((object)("Cant process Unexpected Item " + item.m_shared.m_name));
			return false;
		}
		string shortItemName = item.SCName();
		if (!TestItemNamePrefix(container, shortItemName, item))
		{
			return TestItemNamePostfix(container, shortItemName, item);
		}
		return true;
	}

	public static bool ContainerHasSameItemType(Container container, ItemData item)
	{
		//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_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: 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_00eb: Unknown result type (might be due to invalid IL or missing references)
		if (item.m_shared.m_name.Length < 7)
		{
			return false;
		}
		ItemType itemType = item.m_shared.m_itemType;
		string shortItemName = item.SCName();
		int num;
		if ((!IsTrophie(itemType) || !HaveMatchingItem(container, (ItemData _) => IsTrophie(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsTool(itemType) || !HaveMatchingItem(container, (ItemData _) => IsTool(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsAmmo(itemType) || !HaveMatchingItem(container, (ItemData _) => IsAmmo(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))) && (!IsArmor(itemType) || !HaveMatchingItem(container, (ItemData _) => IsArmor(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName))))
		{
			if (IsWeapon(itemType))
			{
				num = (HaveMatchingItem(container, (ItemData _) => IsWeapon(_.m_shared.m_itemType) && !_.SCName().Equals(shortItemName)) ? 1 : 0);
				if (num != 0)
				{
					goto IL_00c6;
				}
			}
			else
			{
				num = 0;
			}
			goto IL_00ff;
		}
		num = 1;
		goto IL_00c6;
		IL_00ff:
		return (byte)num != 0;
		IL_00c6:
		Console.instance.Print($"{Localization.instance.Localize(item.m_shared.m_name)} routed because target container has same item type {item.m_shared.m_itemType}");
		goto IL_00ff;
	}

	public static bool ContainerHasSimilarGroupItems(Container container, ItemData item)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: 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)
		if (item.m_shared.m_name.Length < 7)
		{
			return false;
		}
		string shortItemName = item.m_shared.m_name.SCName();
		ItemType itemType = item.m_shared.m_itemType;
		int num;
		if ((int)itemType != 0)
		{
			num = (HaveMatchingItem(container, (ItemData _) => _.m_shared.m_itemType == itemType && !_.SCName().Equals(shortItemName)) ? 1 : 0);
			if (num != 0)
			{
				Console.instance.Print($"{Localization.instance.Localize(item.m_shared.m_name)} routed because target container has same item type (fuzzy) {item.m_shared.m_itemType}");
			}
		}
		else
		{
			num = 0;
		}
		return (byte)num != 0;
	}

	private static bool TestItemNamePrefix(Container container, string shortItemName, ItemData item)
	{
		foreach (string prefix in prefixItemGroups)
		{
			if (shortItemName.StartsWith(prefix) && HaveMatchingItem(container, (ItemData _) => _.m_shared.m_name.StartsWith("$item_" + prefix) && !_.SCName().Equals(shortItemName)))
			{
				Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item with Prefix " + prefix);
				return true;
			}
		}
		return false;
	}

	private static bool TestItemNamePostfix(Container container, string shortItemName, ItemData item)
	{
		foreach (string postfix in postfixItemGroups)
		{
			if (shortItemName.EndsWith(postfix) && HaveMatchingItem(container, (ItemData _) => _.m_shared.m_name.EndsWith(postfix) && !_.SCName().Equals(shortItemName)))
			{
				Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item with Postfix " + postfix);
				return true;
			}
		}
		return false;
	}

	private static bool TestConfiguredGroups(Container container, string shortItemName, ItemData item, ICollection<string> grKeys = null)
	{
		foreach (string item2 in grKeys ?? Groups.Keys)
		{
			if (Groups.ContainsKey(item2))
			{
				ISet<string> set = Groups[item2];
				if (TestGroup(shortItemName, container, set))
				{
					Console.instance.Print(Localization.instance.Localize(item.m_shared.m_name) + " routed because target container has item from group " + item2 + " : [" + string.Join(",", set) + "]");
					return true;
				}
			}
		}
		return false;
	}

	private static ICollection<string> FindMatchingGroups(Container container, string shortItemName, ItemData item, ICollection<string> grKeys = null)
	{
		ICollection<string> obj = grKeys ?? Groups.Keys;
		List<string> list = new List<string>();
		foreach (string item2 in obj)
		{
			if (Groups.ContainsKey(item2))
			{
				ISet<string> group = Groups[item2];
				if (TestGroup(shortItemName, container, group))
				{
					list.Add(item2);
				}
			}
		}
		return list;
	}

	private static bool TestGroup(string shortItemName, Container container, ICollection<string> group)
	{
		if (group.Contains(shortItemName))
		{
			foreach (string iname in group)
			{
				if (!iname.Equals(shortItemName) && HaveMatchingItem(container, (ItemData _) => _.SCName().Equals(iname)))
				{
					return true;
				}
			}
		}
		return false;
	}

	private static bool HaveMatchingItem(Container container, Func<ItemData, bool> predicate)
	{
		foreach (ItemData item in container.GetInventory().m_inventory)
		{
			if (predicate(item))
			{
				return true;
			}
		}
		return false;
	}

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

	private static bool IsWeapon(ItemType _)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Invalid comparison between Unknown and I4
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Invalid comparison between Unknown and I4
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Invalid comparison between Unknown and I4
		if ((int)_ != 3 && (int)_ != 4 && (int)_ != 14)
		{
			return (int)_ == 5;
		}
		return true;
	}

	private static bool IsTrophie(ItemType _)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		return (int)_ == 13;
	}

	private static bool IsTool(ItemType _)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		return (int)_ == 19;
	}

	private static bool IsAmmo(ItemType _)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		return (int)_ == 9;
	}

	public static void Clear()
	{
		prefixItemGroups.Clear();
		postfixItemGroups.Clear();
		Groups.Clear();
	}
}
public static class ItemGroupUtils
{
	private static readonly Predicate<string> IsItemSupported = (string itemName) => itemName.StartsWith("$item_") || itemName.StartsWith("$mod_");

	public static void RegisterNewGroup(Inventory inventory)
	{
		List<string> list = ExtractUniqueItemNames(inventory);
		if (list.Count > 1)
		{
			RegisterNewGroup((ICollection<string>)list);
		}
	}

	public static void RegisterNewGroup(ICollection<string> names)
	{
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Expected O, but got Unknown
		if (!names.Any())
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, "No new items to create a group from.", 0, (Sprite)null);
			return;
		}
		Mod.ignoreUpdate = true;
		ConfigDefinition val = new ConfigDefinition("ItemGroup", "userGroup" + DateTimeOffset.UtcNow.ToUnixTimeSeconds());
		Mod.config.Bind<string>(val, string.Join(",", names), Mod.groupDescr("user-added items-group based on item-names list"));
		ConfigEntry<string> val2 = default(ConfigEntry<string>);
		if (Mod.config.TryGetEntry<string>(val, ref val2) && val2.Value.Length > 0)
		{
			ISet<string> set = ParseGroupConfigEntry(val2);
			ItemGroups.Groups.Add(val.Key, set);
			ManualLogSource log = Mod.log;
			if (log != null)
			{
				log.LogInfo((object)string.Format("parsed items group '{0}': [{1}] ({2})", val.Key, string.Join(",", set), set.Count));
			}
			NotifyPlayer(set.Count, "Registered new group of {0} items.");
		}
	}

	public static void MergeAllToSingleGroup(string targetGroupId, List<string> groupIds, List<string> newItems)
	{
		HashSet<string> hashSet = groupIds.Filter((string _) => !_.Equals(targetGroupId)).FlatMap((string _) => ItemGroups.Groups[_]).ToList()
			.Concat(newItems)
			.ToHashSet();
		if (!ItemGroups.Groups.ContainsKey(targetGroupId))
		{
			RegisterNewGroup((ICollection<string>)hashSet);
		}
		else
		{
			hashSet = hashSet.Except(ItemGroups.Groups[targetGroupId]).ToHashSet();
			if (!hashSet.Any())
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null);
			}
			else
			{
				AddToItemsGroup(targetGroupId, hashSet);
				NotifyPlayer(hashSet.Count, "Added {0} new items to existing group.");
			}
		}
		foreach (string item in groupIds.Filter((string _) => !_.Equals(targetGroupId)))
		{
			Mod.log.LogInfo((object)("flattened group : " + item));
			ClearItemsGroup(item);
		}
	}

	public static void ExtendGroup(string targetGroupId, List<string> groupIds, List<string> newItems)
	{
		List<string> second = groupIds.FlatMap((string _) => ItemGroups.Groups[_]).Intersect(newItems).ToList();
		HashSet<string> hashSet = newItems.Except(second).ToHashSet();
		if (!ItemGroups.Groups.ContainsKey(targetGroupId))
		{
			RegisterNewGroup((ICollection<string>)hashSet);
			return;
		}
		if (!hashSet.Any())
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null);
			return;
		}
		AddToItemsGroup(targetGroupId, hashSet);
		NotifyPlayer(hashSet.Count, "Added {0} new items to existing group.");
	}

	public static void ExtendAndMerge(string targetGroupId, List<string> groupIds, List<string> newItems)
	{
		foreach (string item in groupIds.Filter((string _) => !_.Equals(targetGroupId)))
		{
			List<string> items = newItems.Intersect(ItemGroups.Groups[item]).ToList();
			RemoveFromItemsGroup(item, items);
		}
		if (!ItemGroups.Groups.ContainsKey(targetGroupId))
		{
			RegisterNewGroup((ICollection<string>)newItems);
			return;
		}
		HashSet<string> hashSet = newItems.Except(ItemGroups.Groups[targetGroupId]).ToHashSet();
		if (!hashSet.Any())
		{
			((Character)Player.m_localPlayer).Message((MessageType)2, "Existing group already contained all items", 0, (Sprite)null);
			return;
		}
		AddToItemsGroup(targetGroupId, hashSet);
		NotifyPlayer(hashSet.Count, "Added {0} new items to existing group.");
	}

	public static ConfigEntry<string> AddToItemListConfig(ICollection<string> names, ISet<string> targetSet, ConfigEntry<string> configEntry, string uiMessage)
	{
		foreach (string name in names)
		{
			targetSet.Add(name);
		}
		Mod.ignoreUpdate = true;
		configEntry.Value = string.Join(",", targetSet);
		NotifyPlayer(names.Count, uiMessage);
		return configEntry;
	}

	private static void NotifyPlayer(int count, string uiMessage)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		((Character)Player.m_localPlayer).Message((MessageType)2, string.Format(uiMessage, count), 0, (Sprite)null);
		if (Mod.effectFeedbackEnabled.Value)
		{
			Vector3 position = ((Component)InventoryGui.instance.m_currentContainer).gameObject.transform.position;
			Player.m_localPlayer.m_skillLevelupEffects.Create(position, Quaternion.identity, (Transform)null, 1f, -1);
		}
	}

	public static List<Tuple<string, List<string>>> FindIntersections(List<string> names)
	{
		List<Tuple<string, List<string>>> list = new List<Tuple<string, List<string>>>();
		foreach (string item in ItemGroups.Groups.Keys.ToList())
		{
			List<string> list2 = ItemGroups.Groups[item].Intersect(names).ToList();
			if (list2.Any())
			{
				list.Add(new Tuple<string, List<string>>(item, list2));
			}
		}
		return list.OrderByDescending((Tuple<string, List<string>> tt) => tt.Item2.Count).ToList();
	}

	public static List<string> ExtractUniqueItemNames(Inventory inventory)
	{
		foreach (string item in inventory.m_inventory.Map((ItemData invi) => invi.m_shared.m_name).Filter((string _) => !IsItemSupported(_)).ToList())
		{
			Mod.log.LogWarning((object)("Unsupported item name " + item));
		}
		return inventory.m_inventory.Map((ItemData invi) => invi.m_shared.m_name).Filter((string _) => IsItemSupported(_)).Distinct()
			.Map((string _) => _.SCName())
			.ToList();
	}

	public static ISet<string> ParseGroupConfigEntry(ConfigEntry<string> configEntry)
	{
		return new HashSet<string>(configEntry.Value.Split(new char[1] { ',' }).Map((string _) => _.SCName().Replace(" ", "")));
	}

	private static void AddToItemsGroup(string groupId, ICollection<string> items)
	{
		foreach (string item in items)
		{
			ItemGroups.Groups[groupId].Add(item);
		}
		SaveItemsGroup(groupId, ItemGroups.Groups[groupId]);
	}

	private static void RemoveFromItemsGroup(string groupId, ICollection<string> items)
	{
		foreach (string item in items)
		{
			ItemGroups.Groups[groupId].Remove(item);
		}
		SaveItemsGroup(groupId, ItemGroups.Groups[groupId]);
	}

	private static void ClearItemsGroup(string flattenedGroupId)
	{
		ItemGroups.Groups[flattenedGroupId].Clear();
		SaveItemsGroup(flattenedGroupId, ItemGroups.Groups[flattenedGroupId]);
	}

	private static void SaveItemsGroup(string groupId, ICollection<string> groupItems)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0017: Expected O, but got Unknown
		ConfigEntry<string> val = default(ConfigEntry<string>);
		if (Mod.config.TryGetEntry<string>(new ConfigDefinition("ItemGroup", groupId), ref val))
		{
			Mod.ignoreUpdate = true;
			val.Value = string.Join(",", groupItems);
		}
	}
}
[BepInPlugin("flueno.SmartContainers", "Smart Containers Mod", "1.7.0")]
public class Mod : BaseUnityPlugin
{
	internal readonly Harmony harmony;

	internal readonly Assembly assembly;

	public static ManualLogSource log;

	public static ConfigFile config;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<bool> groupingEnabled;

	public static ConfigEntry<bool> itemTypeGroupsEnabled;

	public static ConfigEntry<bool> fuzzyGroupingEnabled;

	public static ConfigEntry<bool> onlyStackableItems;

	public static ConfigEntry<ConcurrentChestModificationWorkaround> concurrencyWorkaround;

	public static ConfigEntry<bool> hudMessageEnabled;

	public static ConfigEntry<bool> audioFeedbackEnabled;

	public static ConfigEntry<bool> effectFeedbackEnabled;

	public static ConfigEntry<string> hudMessageText;

	public static ConfigEntry<int> range;

	public static ConfigEntry<KeyboardShortcut> keyModifier;

	public static ConfigEntry<string> gamepadKey1;

	public static ConfigEntry<KeyboardShortcut> gamepadKey2;

	public static ConfigEntry<KeyboardShortcut> groupingKeyModifier;

	public static ConfigEntry<bool> createGroupBtnEnabled;

	public static ConfigEntry<bool> mergePromptEnabled;

	public static ConfigEntry<Vector2> createGroupBtnPos;

	public static ConfigEntry<bool> unloadAllEnabled;

	public static ConfigEntry<bool> unloadAllInsteadStackBtn;

	public static ConfigEntry<Vector2> unloadAllBtnPos;

	public static ConfigEntry<KeyboardShortcut> unloadAllItemsGroupKeyModifier;

	public static ConfigEntry<KeyboardShortcut> unloadAllSkipItemsGroupKeyModifier;

	public static ConfigEntry<bool> unloadForceGrouping;

	public static ConfigEntry<string> unloadAllItemsList;

	public static ConfigEntry<string> unloadAllSkipList;

	public static ConfigEntry<string> unloadAllGroupsList;

	public static ConfigEntry<string> unloadAllPrefixItemGroups;

	public static ConfigEntry<string> unloadAllPostfixItemGroups;

	public static ConfigEntry<bool> unloadAllMaterialsFiltering;

	public static ConfigEntry<bool> unloadAllTrophiesFiltering;

	public static ConfigEntry<bool> unloadAllConsumableFiltering;

	public static bool ignoreUpdate = false;

	public static readonly ICollection<string> systemGroupKeys = new HashSet<string> { "valuables", "ore", "rock", "ingots", "wood", "mushrooms", "berries", "vegetables", "cookedMeat", "food" };

	public Mod()
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected O, but got Unknown
		harmony = new Harmony("flueno.SmartContainers");
		assembly = Assembly.GetExecutingAssembly();
		config = ((BaseUnityPlugin)this).Config;
		log = ((BaseUnityPlugin)this).Logger;
	}

	public void Start()
	{
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Expected O, but got Unknown
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_023b: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_054b: Unknown result type (might be due to invalid IL or missing references)
		((BaseUnityPlugin)this).Config.Bind<int>("General", "NexusID", 332, "Nexus mod ID");
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "enabled", true, "Enables this mod");
		MigrateConfig(ConfigOrphanedEntries());
		onlyStackableItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "onlyStackableItems", true, "Rearranges only stackable items");
		hudMessageEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "hudMessageEnabled", true, "Enables hud message indicating that item was routed & placed to some other chest");
		hudMessageText = ((BaseUnityPlugin)this).Config.Bind<string>("General", "hudMessageText", "Routed to another Chest", "HUD message consists of Icon, item-name plus this text.");
		range = ((BaseUnityPlugin)this).Config.Bind<int>("General", "range", 14, new ConfigDescription("Range within which containers will participate in resources arrangement.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 99), Array.Empty<object>()));
		keyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "hkeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "Change only if you wish to have even longer than ctrl+click combination (holding ctrl is mandatory since it's a 'move-stack' ingame key)");
		gamepadKey1 = ((BaseUnityPlugin)this).Config.Bind<string>("General", "gamepadKey1", "JoyLTrigger", "first part of gamepads transfer-item key-combo");
		gamepadKey2 = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "gamepadKey2", new KeyboardShortcut((KeyCode)332, Array.Empty<KeyCode>()), "second part of gamepads transfer-item key-combo");
		audioFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "audioFeedbackEnabled", true, "Enables playing of sound on successful items transfer");
		effectFeedbackEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "effectFeedbackEnabled", true, "Enables highlighting of end-target chests where items have been transferred.");
		concurrencyWorkaround = ((BaseUnityPlugin)this).Config.Bind<ConcurrentChestModificationWorkaround>("General", "concurrentChestModificationWorkaround", ConcurrentChestModificationWorkaround.ExcludeContainersOpenedByOthers, "There are rare possibility of items loss if two players simultaneously (within a ~second) modify same containers inventory. Options are: ignore possible issue; ignore 'opened' chests; block mod if any other nearby player opened a chest");
		groupingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "enabled", true, "Enables distributing items to containers with 'same-kinded' items (used if no nearby containers contain 'same item')");
		itemTypeGroupsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "itemTypeGroupsEnabled", true, "Enable grouping by item-types (Trophie, Tool, Ammo, Armor, Weapon).");
		fuzzyGroupingEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "fuzzyGroupingEnabled", false, "Enable grouping by more broad criteria.");
		groupingKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Grouping", "groupingKeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), " Change to 'LeftControl + LeftShift' if you want to trigger grouping with a separate hotkey (ctrl+shift+click)(holding ctrl is mandatory since it's a 'move-stack' ingame key)");
		createGroupBtnEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "createGroupBtnEnabled", true, "Adds to the chest UI button [☼] which creates items-group based on the current items set in the chest.");
		mergePromptEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grouping", "mergePromptEnabled", true, "In case when createGroupBtn clicked and chest already contains some members of one ore more groups - dialog showed with option to merge items & groups into a single group.");
		createGroupBtnPos = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Grouping", "createGroupBtnPos", new Vector2(1.5f, 10.7f), "Adjusts btn position on inventory ui. →x:1.5..-10 ↓y:0.4..10.7  bottom-left: (1.5f, 10.7f) top-right:(-10f, 0.4f) bottom-right:(-10f, 10.7f)");
		((BaseUnityPlugin)this).Config.Bind<string>("PrefixedItemGroups", "prefixes", "trophy,mead,arrow,armor,cape,helmet,atgeir,bow,battleaxe,knife,mace,shield,sledge,spear,sword,tankard,club,mushroom,arrow", groupDescr("If both item names start with same 'prefix' - they are considered to have same group. I.e. arrowFire & arrowFlint"));
		((BaseUnityPlugin)this).Config.Bind<string>("PostfixedItemGroups", "posfixes", "cone,seeds,pelt,hide,berries", groupDescr("If both item names end with same 'postfix' - they are considered to have same group. I.e. carrotSeeds & turnipSeeds"));
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "valuables", "ruby,coins,amber,amberpearl", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "ore", "copperore,flametalore,ironore,silverore,tinore,ironscrap,blackmetalscrap", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "rock", "stone,flint,obsidian", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "ingots", "copper,bronze,flametal,iron,silver,tin,blackmetal", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "wood", "wood,finewood,corewood,elderbark,roundlog", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "mushrooms", "Mushroom,MushroomBlue,MushroomYellow,mushroomcommon", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "berries", "Blueberries,raspberries,cloudberries,honey", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "vegetables", "Carrot,Turnip", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "cookedMeat", "CookedLoxMeat,NeckTailGrilled,MeatCooked,FishCooked,SerpentMeatCooked", groupDescr());
		((BaseUnityPlugin)this).Config.Bind<string>("ItemGroup", "food", "CarrotSoup,Sausages,QueensJam,SerpentStew,TurnipStew,BloodPudding", groupDescr());
		unloadAllEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "enabled", false, "Enables Unload-all option & UI button [\\||/]. Allows to batch-unload all eligible items from players inventory to their corresponding stacks & groups in nearby chests.");
		unloadAllInsteadStackBtn = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "nativeButton", false, "Use existing 'place-stacks' UI button for unloading. If disabled - new UI button [\\||/] will be created.");
		unloadAllBtnPos = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Unload", "btnPos", new Vector2(1.5f, 8.15f), (ConfigDescription)null);
		unloadAllItemsGroupKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Unload", "addToItemsFilterKeyModifier", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "If pressed - overrides createGroupBtn behaviour by passing item-names to unload 'itemsList' instead of creating new items group");
		unloadForceGrouping = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "alwaysGrouping", true, "If enabled - check for groupingKeyModifier pressed is ignored for 'unload' button");
		unloadAllSkipItemsGroupKeyModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Unload", "addToSkipItemsFilterKeyModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "If pressed - overrides createGroupBtn behaviour by passing item-names to unload 'itemsSkipList' instead of creating new items group");
		unloadAllItemsList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "itemsList", "", groupDescr("List of item-names allowed to be 'unloaded'"));
		unloadAllSkipList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "itemsSkipList", "", groupDescr("List of item-names to exclude from being 'unloaded'"));
		unloadAllGroupsList = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "groupsList", "valuables,ore,wood,mushrooms", "List of items group-ids from [ItemGroup] config section allowed to be 'unloaded'");
		unloadAllPrefixItemGroups = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "prefixItemGroups", "trophy", (ConfigDescription)null);
		unloadAllPostfixItemGroups = ((BaseUnityPlugin)this).Config.Bind<string>("Unload", "postfixItemGroups", "seeds", (ConfigDescription)null);
		unloadAllMaterialsFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "materialsFiltering", true, "allow all Materials to be 'unloaded'");
		unloadAllTrophiesFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "trophiesFiltering", true, "allow all Trophies to be 'unloaded'");
		unloadAllConsumableFiltering = ((BaseUnityPlugin)this).Config.Bind<bool>("Unload", "consumableFiltering", false, "allow all Consumables to be 'unloaded'");
		if (modEnabled.Value)
		{
			ItemGroups.ParseConfig();
			UnloadItems.ParseConfig();
			ContainersTracker.Init();
			Gui_Patch.Init();
			((BaseUnityPlugin)this).Config.SettingChanged += HandleConfigUpdate;
			harmony.PatchAll(assembly);
		}
	}

	public static ConfigDescription groupDescr(string descr = "Items-group based on item-names list")
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_0028: Expected O, but got Unknown
		return new ConfigDescription(descr, (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				CustomDrawer = TextAreaDrawer
			}
		});
	}

	private static void TextAreaDrawer(ConfigEntryBase entry)
	{
		GUILayout.ExpandHeight(true);
		GUILayout.ExpandWidth(true);
		entry.BoxedValue = GUILayout.TextArea((string)entry.BoxedValue, (GUILayoutOption[])(object)new GUILayoutOption[2]
		{
			GUILayout.ExpandWidth(true),
			GUILayout.ExpandHeight(true)
		});
	}

	private void HandleConfigUpdate(object sender, SettingChangedEventArgs e)
	{
		if (ignoreUpdate)
		{
			ignoreUpdate = false;
			log.LogInfo((object)$"SettingChangedEventArgs (ignored) {e.ChangedSetting.Definition}");
			return;
		}
		Gui_Patch.Clean();
		Gui_Patch.Init();
		ItemGroups.Clear();
		ItemGroups.ParseConfig();
		UnloadItems.Clear();
		UnloadItems.ParseConfig();
	}

	private void OnDestroy()
	{
		harmony.UnpatchSelf();
		((BaseUnityPlugin)this).Config.Reload();
		Gui_Patch.Clean();
		ItemGroups.Clear();
		UnloadItems.Clear();
		ContainersTracker.containerList.Clear();
	}

	public static bool isSystemGroup(string groupId)
	{
		return systemGroupKeys.Contains(groupId);
	}

	public static void PlayEffect(bool allowed, string prefabName, Vector3 pos)
	{
		//IL_0019: 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)
		if (allowed)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
			if ((Object)(object)prefab != (Object)null)
			{
				Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity);
			}
			else
			{
				log.LogWarning((object)("Failed to locate FeedbackEffect " + prefabName + " prefab"));
			}
		}
	}

	public static Dictionary<ConfigDefinition, string> ConfigOrphanedEntries()
	{
		return Traverse.Create((object)config).Property("OrphanedEntries", (object[])null).GetValue<Dictionary<ConfigDefinition, string>>();
	}

	private static void MigrateConfig(Dictionary<ConfigDefinition, string> orphans)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		//IL_0038: 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_0051: Expected O, but got Unknown
		//IL_0051: Expected O, but got Unknown
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Expected O, but got Unknown
		//IL_0075: Expected O, but got Unknown
		//IL_0080: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0099: Expected O, but got Unknown
		//IL_0099: Expected O, but got Unknown
		//IL_00a4: 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_00bd: Expected O, but got Unknown
		//IL_00bd: Expected O, but got Unknown
		//IL_00c8: 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_00e1: Expected O, but got Unknown
		//IL_00e1: Expected O, but got Unknown
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Expected O, but got Unknown
		if (orphans.ContainsKey(new ConfigDefinition("ItemGroup", "coockedMeat")))
		{
			orphans.Remove(new ConfigDefinition("ItemGroup", "coockedMeat"));
		}
		ChangeKey<bool>(orphans, new ConfigDefinition("General", "groupingEnabled"), new ConfigDefinition("Grouping", "enabled"));
		ChangeKey<bool>(orphans, new ConfigDefinition("General", "itemTypeGroupsEnabled"), new ConfigDefinition("Grouping", "itemTypeGroupsEnabled"));
		ChangeKey<bool>(orphans, new ConfigDefinition("General", "fuzzyGroupingEnabled"), new ConfigDefinition("Grouping", "fuzzyGroupingEnabled"));
		ChangeKey<bool>(orphans, new ConfigDefinition("General", "createGroupBtnEnabled"), new ConfigDefinition("Grouping", "createGroupBtnEnabled"));
		ChangeKey<Vector2>(orphans, new ConfigDefinition("General", "createGroupBtnPos"), new ConfigDefinition("Grouping", "createGroupBtnPos"));
	}

	private static void ChangeKey<T>(Dictionary<ConfigDefinition, string> orphans, ConfigDefinition dkey, ConfigDefinition dkeyNew)
	{
		if (orphans.ContainsKey(dkey))
		{
			orphans.Add(dkeyNew, orphans[dkey]);
			orphans.Remove(dkey);
		}
	}
}
public enum ConcurrentChestModificationWorkaround
{
	None,
	ExcludeContainersOpenedByOthers,
	BlockIfOtherContainersAreOpened
}
internal static class ConcurrentChestModificationWorkaroundMethods
{
	public static bool SkipOpenedOthers(this ConcurrentChestModificationWorkaround option)
	{
		return option == ConcurrentChestModificationWorkaround.ExcludeContainersOpenedByOthers;
	}

	public static bool Ignore(this ConcurrentChestModificationWorkaround option)
	{
		return option == ConcurrentChestModificationWorkaround.None;
	}

	public static bool BlockIfAnyOtherOpened(this ConcurrentChestModificationWorkaround option)
	{
		return option == ConcurrentChestModificationWorkaround.BlockIfOtherContainersAreOpened;
	}
}
internal static class KeyboardShortcutMethods
{
	public static bool IsPressedOrNone(this KeyboardShortcut shortcut)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Invalid comparison between Unknown and I4
		if (!((KeyboardShortcut)(ref shortcut)).IsPressed())
		{
			return (int)((KeyboardShortcut)(ref shortcut)).MainKey == 0;
		}
		return true;
	}

	public static bool MainPressed(this KeyboardShortcut shortcut)
	{
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		return Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey);
	}
}
internal static class ItemDataMethods
{
	public static string SCName(this string itemName)
	{
		return itemName.ToLower().Replace("$item_", "").Replace("_", "");
	}

	public static string SCName(this ItemData itemDrop)
	{
		return itemDrop.m_shared.m_name.SCName();
	}
}
internal static class EnumerableMethods
{
	public static IEnumerable<R> Map<T, R>(this IEnumerable<T> self, Func<T, R> selector)
	{
		return self.Select(selector);
	}

	public static T Reduce<T>(this IEnumerable<T> self, Func<T, T, T> func)
	{
		return self.Aggregate(func);
	}

	public static T Reduce<T>(this IEnumerable<T> self, T seed, Func<T, T, T> func)
	{
		return self.Aggregate(seed, func);
	}

	public static IEnumerable<R> FlatMap<T, R>(this IEnumerable<T> self, Func<T, IEnumerable<R>> func)
	{
		return self.SelectMany(func);
	}

	public static IEnumerable<T> Filter<T>(this IEnumerable<T> self, Func<T, bool> predicate)
	{
		return self.Where(predicate);
	}
}
public static class UnloadItems
{
	private static ISet<string> unloadAllItemsList = new HashSet<string>();

	private static ISet<string> unloadAllItemsSkipList = new HashSet<string>();

	public static ICollection<string> unloadAllGroupsList = new HashSet<string>();

	private static ICollection<string> unloadAllPrefixItemGroups = new HashSet<string>();

	private static ICollection<string> unloadAllPostfixItemGroups = new HashSet<string>();

	public static void ParseConfig()
	{
		if (Mod.unloadAllPrefixItemGroups.Value.Length > 0)
		{
			unloadAllPrefixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllPrefixItemGroups);
		}
		if (Mod.unloadAllPostfixItemGroups.Value.Length > 0)
		{
			unloadAllPostfixItemGroups = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllPostfixItemGroups);
		}
		if (Mod.unloadAllItemsList.Value.Length > 0)
		{
			unloadAllItemsList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllItemsList);
		}
		if (Mod.unloadAllSkipList.Value.Length > 0)
		{
			unloadAllItemsSkipList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllSkipList);
		}
		if (Mod.unloadAllGroupsList.Value.Length > 0)
		{
			unloadAllGroupsList = ItemGroupUtils.ParseGroupConfigEntry(Mod.unloadAllGroupsList);
		}
	}

	public static void UnloadAllItems(Inventory playerInv)
	{
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		List<ItemData> list = playerInv.m_inventory.Filter((ItemData i) => !i.m_equipped).Map((ItemData i) => (i, i.m_shared.m_name.SCName())).Filter<(ItemData, string)>(((ItemData i, string) tuple) => !Mod.onlyStackableItems.Value || tuple.i.m_shared.m_maxStackSize > 1)
			.Filter<(ItemData, string)>(((ItemData i, string) tuple) => !unloadAllItemsSkipList.Contains(tuple.Item2))
			.Filter<(ItemData, string)>(((ItemData i, string) tuple) => (Mod.unloadAllMaterialsFiltering.Value && (int)tuple.i.m_shared.m_itemType == 1) || (Mod.unloadAllTrophiesFiltering.Value && (int)tuple.i.m_shared.m_itemType == 13) || (Mod.unloadAllConsumableFiltering.Value && (int)tuple.i.m_shared.m_itemType == 2) || (unloadAllItemsList.Any() && unloadAllItemsList.Contains(tuple.Item2)) || (unloadAllPrefixItemGroups.Any() && TestList((string _) => tuple.Item2.StartsWith(_), unloadAllPrefixItemGroups)) || (unloadAllPostfixItemGroups.Any() && TestList((string _) => tuple.Item2.EndsWith(_), unloadAllPostfixItemGroups)) || (unloadAllGroupsList.Any() && unloadAllGroupsList.Any((string groupId) => TestList((string _) => tuple.Item2.Equals(_), ItemGroups.Groups[groupId]))))
			.Map<(ItemData, string), ItemData>(((ItemData i, string) tuple) => tuple.i)
			.ToList();
		bool flag = false;
		foreach (ItemData item in list)
		{
			if (Inventory_Patch.TryAddToNearBy(item, allowCurrent: true, Mod.unloadForceGrouping.Value))
			{
				playerInv.RemoveItem(item);
				if (!flag)
				{
					Mod.PlayEffect(Mod.audioFeedbackEnabled.Value, "sfx_lootspawn", ((Character)Player.m_localPlayer).GetCenterPoint());
					flag = true;
				}
			}
		}
	}

	public static void AddToUnloadAllItemsFilter(Inventory inventory)
	{
		Mod.unloadAllItemsList = AddToItemListConfig(inventory, unloadAllItemsList, Mod.unloadAllItemsList, "Added {0} items to unload-items filter");
	}

	public static void AddToUnloadAllItemsSkipList(Inventory inventory)
	{
		Mod.unloadAllSkipList = AddToItemListConfig(inventory, unloadAllItemsSkipList, Mod.unloadAllSkipList, "Added {0} items to unload-skip-items list");
	}

	private static ConfigEntry<string> AddToItemListConfig(Inventory inventory, ISet<string> targetSet, ConfigEntry<string> configEntry, string uiMessage)
	{
		List<string> list = ItemGroupUtils.ExtractUniqueItemNames(inventory);
		if (list.Count < 1)
		{
			return configEntry;
		}
		return ItemGroupUtils.AddToItemListConfig(list, targetSet, configEntry, uiMessage);
	}

	private static bool TestList(Func<string, bool> predicate, ICollection<string> group)
	{
		foreach (string item in group)
		{
			if (predicate(item))
			{
				return true;
			}
		}
		return false;
	}

	public static void Clear()
	{
		unloadAllItemsList.Clear();
		unloadAllItemsSkipList.Clear();
		unloadAllGroupsList.Clear();
		unloadAllPrefixItemGroups.Clear();
		unloadAllPostfixItemGroups.Clear();
	}
}