Decompiled source of KMartBoysMustHaveMod v1.13.1

K-MartBoysMustHaveMod.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace KMartBoysMustHaveMod;

[HarmonyPatch(typeof(CraftingStation), "Interact")]
internal static class CraftingStation_Interact_AutoRepair_Patch
{
	private static readonly MethodInfo CanRepair = AccessTools.Method(typeof(InventoryGui), "CanRepair", new Type[1] { typeof(ItemData) }, (Type[])null);

	private static void Postfix(CraftingStation __instance, Humanoid user, bool repeat)
	{
		//IL_0126: 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_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013f: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (repeat || !KMartBoysPlugin.ModEnabled.Value || !KMartBoysPlugin.AutoRepairEnabled.Value || KMartBoysPlugin.OtherRepairModLoaded)
			{
				return;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer || (Object)(object)val.GetCurrentCraftingStation() != (Object)(object)__instance)
			{
				return;
			}
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || CanRepair == null)
			{
				return;
			}
			List<ItemData> list = new List<ItemData>();
			((Humanoid)val).GetInventory().GetWornItems(list);
			int num = 0;
			foreach (ItemData item in list)
			{
				if (item != null && (bool)CanRepair.Invoke(instance, new object[1] { item }))
				{
					float maxDurability = item.GetMaxDurability();
					if (!(item.m_durability >= maxDurability))
					{
						item.m_durability = maxDurability;
						num++;
					}
				}
			}
			if (num > 0)
			{
				if (__instance.m_repairItemDoneEffects != null)
				{
					__instance.m_repairItemDoneEffects.Create(((Component)__instance).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
				if (KMartBoysPlugin.AutoRepairShowMessage.Value)
				{
					((Character)val).Message((MessageType)2, "Repaired " + num + " item" + ((num == 1) ? "" : "s"), 0, (Sprite)null, false);
				}
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("autorepair", "Auto-repair failed: " + ex.Message);
		}
	}
}
public enum ClockAnchor
{
	TopLeft,
	TopCenter,
	TopRight,
	BottomLeft,
	BottomCenter,
	BottomRight
}
internal static class ClockHud
{
	private const string ObjectName = "KMartBoys_Clock";

	private const float UpdateInterval = 0.25f;

	private static TextMeshProUGUI _text;

	private static float _nextUpdate;

	private static readonly Dictionary<string, string> WeatherNames = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
	{
		{ "Clear", "Clear" },
		{ "Twilight_Clear", "Clear" },
		{ "Heath clear", "Clear" },
		{ "nofogts", "Clear" },
		{ "Mistlands_clear", "Clear" },
		{ "Misty", "Misty" },
		{ "Ashlands_misty", "Misty" },
		{ "DeepForest Mist", "Forest Mist" },
		{ "Darklands_dark", "Dark" },
		{ "Rain", "Rain" },
		{ "LightRain", "Light Rain" },
		{ "Mistlands_rain", "Rain" },
		{ "SwampRain", "Swamp Rain" },
		{ "ThunderStorm", "Thunderstorm" },
		{ "Mistlands_thunder", "Thunderstorm" },
		{ "Snow", "Snow" },
		{ "Twilight_Snow", "Snow" },
		{ "SnowStorm", "Snowstorm" },
		{ "Twilight_SnowStorm", "Snowstorm" },
		{ "Ashrain", "Ash Rain" },
		{ "Ashlands_ashrain", "Ash Rain" },
		{ "Ashlands_storm", "Ash Storm" },
		{ "Ashlands_CinderRain", "Cinder Rain" },
		{ "Eikthyr", "Boss Storm" },
		{ "GDKing", "Eerie" },
		{ "Bonemass", "Toxic" },
		{ "Moder", "Blizzard" },
		{ "GoblinKing", "Ominous" },
		{ "Queen", "Ominous" },
		{ "Fader", "Inferno" },
		{ "Crypt", "Crypt" },
		{ "SunkenCrypt", "Sunken Crypt" },
		{ "Caves", "Cave" },
		{ "InfectedMine", "Infested Mine" }
	};

	public static void Tick()
	{
		try
		{
			if (!KMartBoysPlugin.ModEnabled.Value || !KMartBoysPlugin.ClockEnabled.Value || !((Object)(object)Hud.instance != (Object)null) || !((Object)(object)Hud.instance.m_rootObject != (Object)null) || !((Object)(object)EnvMan.instance != (Object)null) || !((Object)(object)Player.m_localPlayer != (Object)null))
			{
				if ((Object)(object)_text != (Object)null && ((Component)_text).gameObject.activeSelf)
				{
					((Component)_text).gameObject.SetActive(false);
				}
				return;
			}
			if ((Object)(object)_text == (Object)null)
			{
				Create();
			}
			if (!((Object)(object)_text == (Object)null))
			{
				if (!((Component)_text).gameObject.activeSelf)
				{
					((Component)_text).gameObject.SetActive(true);
				}
				if (!(Time.unscaledTime < _nextUpdate))
				{
					_nextUpdate = Time.unscaledTime + 0.25f;
					ApplyLayout();
					((TMP_Text)_text).text = BuildText();
				}
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("clock", "Clock error: " + ex.Message);
		}
	}

	private static void Create()
	{
		//IL_008b: 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)
		Transform transform = Hud.instance.m_rootObject.transform;
		Transform val = transform.Find("KMartBoys_Clock");
		if ((Object)(object)val != (Object)null)
		{
			_text = ((Component)val).GetComponent<TextMeshProUGUI>();
		}
		else
		{
			_text = CreateHudText("KMartBoys_Clock", transform);
		}
		if (!((Object)(object)_text == (Object)null))
		{
			GameObject gameObject = ((Component)_text).gameObject;
			((Graphic)_text).raycastTarget = false;
			((TMP_Text)_text).richText = true;
			((TMP_Text)_text).enableAutoSizing = false;
			((TMP_Text)_text).overflowMode = (TextOverflowModes)0;
			((RectTransform)gameObject.transform).sizeDelta = new Vector2(600f, 40f);
			ApplyLayout();
		}
	}

	internal static TextMeshProUGUI CreateHudText(string name, Transform parent)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name);
		val.SetActive(false);
		val.AddComponent<RectTransform>();
		val.transform.SetParent(parent, false);
		TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
		TMP_Text val3 = (TMP_Text)(object)(((Object)(object)Hud.instance != (Object)null) ? Hud.instance.m_hoverName : null);
		if ((Object)(object)val3 != (Object)null && (Object)(object)val3.font != (Object)null)
		{
			((TMP_Text)val2).font = val3.font;
			((TMP_Text)val2).fontSharedMaterial = val3.fontSharedMaterial;
		}
		val.SetActive(true);
		return val2;
	}

	private static void ApplyLayout()
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Expected O, but got Unknown
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = (RectTransform)((TMP_Text)_text).transform;
		Vector2 val2 = default(Vector2);
		TextAlignmentOptions alignment;
		switch (KMartBoysPlugin.ClockPosition.Value)
		{
		case ClockAnchor.TopLeft:
			((Vector2)(ref val2))..ctor(0f, 1f);
			alignment = (TextAlignmentOptions)257;
			break;
		case ClockAnchor.TopRight:
			((Vector2)(ref val2))..ctor(1f, 1f);
			alignment = (TextAlignmentOptions)260;
			break;
		case ClockAnchor.BottomLeft:
			((Vector2)(ref val2))..ctor(0f, 0f);
			alignment = (TextAlignmentOptions)1025;
			break;
		case ClockAnchor.BottomCenter:
			((Vector2)(ref val2))..ctor(0.5f, 0f);
			alignment = (TextAlignmentOptions)1026;
			break;
		case ClockAnchor.BottomRight:
			((Vector2)(ref val2))..ctor(1f, 0f);
			alignment = (TextAlignmentOptions)1028;
			break;
		default:
			((Vector2)(ref val2))..ctor(0.5f, 1f);
			alignment = (TextAlignmentOptions)258;
			break;
		}
		val.anchorMin = val2;
		val.anchorMax = val2;
		val.pivot = val2;
		val.anchoredPosition = new Vector2(KMartBoysPlugin.ClockOffsetX.Value, KMartBoysPlugin.ClockOffsetY.Value);
		((TMP_Text)_text).alignment = alignment;
		((TMP_Text)_text).fontSize = KMartBoysPlugin.ClockFontSize.Value;
		((Graphic)_text).color = KMartBoysPlugin.ClockColor.Value;
	}

	private static string BuildText()
	{
		EnvMan instance = EnvMan.instance;
		int num = Mathf.FloorToInt(Mathf.Repeat(instance.GetDayFraction(), 1f) * 24f * 60f);
		int num2 = Mathf.Max(1, KMartBoysPlugin.ClockMinuteStep.Value);
		int num3 = num - num % num2;
		int num4 = num3 / 60 % 24;
		int num5 = num3 % 60;
		int num6 = ((num4 % 12 == 0) ? 12 : (num4 % 12));
		string text = ((num4 < 12) ? "AM" : "PM");
		string newValue = num6 + ":" + num5.ToString("00") + " " + text;
		EnvSetup currentEnvironment = instance.GetCurrentEnvironment();
		string newValue2 = ((currentEnvironment != null) ? Friendly(currentEnvironment.m_name) : "");
		string newValue3 = Conditions(currentEnvironment, EnvMan.IsNight());
		return (KMartBoysPlugin.ClockFormat.Value ?? "{time}").Replace("\\n", "\n").Replace("{time}", newValue).Replace("{weather}", newValue2)
			.Replace("{conditions}", newValue3)
			.Replace("{day}", instance.GetDay().ToString())
			.Replace("()", "")
			.Replace("[]", "")
			.Trim();
	}

	private static string Conditions(EnvSetup setup, bool night)
	{
		if (setup == null)
		{
			return "";
		}
		List<string> list = new List<string>(2);
		if (setup.m_isFreezing || (night && setup.m_isFreezingAtNight))
		{
			list.Add("Freezing");
		}
		else if (setup.m_isCold || (night && setup.m_isColdAtNight))
		{
			list.Add("Cold");
		}
		if (setup.m_isWet)
		{
			list.Add("Wet");
		}
		return string.Join(", ", list.ToArray());
	}

	private static string Friendly(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return "";
		}
		if (WeatherNames.TryGetValue(raw, out var value))
		{
			return value;
		}
		string text = raw;
		int num = text.LastIndexOf('_');
		if (num >= 0 && num < text.Length - 1)
		{
			text = text.Substring(num + 1);
		}
		StringBuilder stringBuilder = new StringBuilder(text.Length + 4);
		for (int i = 0; i < text.Length; i++)
		{
			char c = text[i];
			if (i > 0 && char.IsUpper(c) && char.IsLower(text[i - 1]))
			{
				stringBuilder.Append(' ');
			}
			stringBuilder.Append((i == 0) ? char.ToUpperInvariant(c) : c);
		}
		return stringBuilder.ToString();
	}
}
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;
}
internal static class ContainerSource
{
	private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

	private static readonly FieldRef<InventoryGui, Container> GuiCurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

	private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

	private const float CacheSeconds = 1f;

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

	private static float _cachedAt = -999f;

	private static readonly Dictionary<string, int> CountMemo = new Dictionary<string, int>();

	private static int _memoFrame = -1;

	public static List<Container> GetContainers()
	{
		if (Time.unscaledTime - _cachedAt >= 1f)
		{
			Rebuild();
		}
		for (int num = Cached.Count - 1; num >= 0; num--)
		{
			if ((Object)(object)Cached[num] == (Object)null)
			{
				Cached.RemoveAt(num);
			}
		}
		return Cached;
	}

	public static void Invalidate()
	{
		_cachedAt = -999f;
		CountMemo.Clear();
	}

	private static void Rebuild()
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		_cachedAt = Time.unscaledTime;
		CountMemo.Clear();
		Cached.Clear();
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			Cached.AddRange(FindAround(((Component)localPlayer).transform.position, KMartBoysPlugin.CraftRadius.Value));
		}
	}

	private static bool IsUsable(Container c, long playerId, Container openContainer)
	{
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		ZNetView val = ContainerNView.Invoke(c);
		if ((Object)(object)val == (Object)null || !val.IsValid())
		{
			return false;
		}
		if (c.GetInventory() == null)
		{
			return false;
		}
		if ((Object)(object)((Component)c).GetComponentInParent<TombStone>() != (Object)null)
		{
			return false;
		}
		if (c.IsInUse() && (Object)(object)c != (Object)(object)openContainer)
		{
			return false;
		}
		if (KMartBoysPlugin.CraftIgnoreMoving.Value && ((Object)(object)c.m_wagon != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)c).GetComponentInParent<Ship>() != (Object)null))
		{
			return false;
		}
		if (KMartBoysPlugin.CraftOnlyPlayerBuilt.Value)
		{
			Piece componentInParent = ((Component)c).GetComponentInParent<Piece>();
			if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsPlacedByPlayer())
			{
				return false;
			}
		}
		if (ContainerCheckAccess != null && !(bool)ContainerCheckAccess.Invoke(c, new object[1] { playerId }))
		{
			return false;
		}
		if (c.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false))
		{
			return false;
		}
		return true;
	}

	public static int Count(string name, int quality, bool matchWorldLevel)
	{
		if (string.IsNullOrEmpty(name))
		{
			return 0;
		}
		if (_memoFrame != Time.frameCount)
		{
			_memoFrame = Time.frameCount;
			CountMemo.Clear();
		}
		string key = name + "|" + quality + "|" + (matchWorldLevel ? "1" : "0");
		if (CountMemo.TryGetValue(key, out var value))
		{
			return value;
		}
		int num = 0;
		foreach (Container container in GetContainers())
		{
			Inventory inventory = container.GetInventory();
			if (inventory != null)
			{
				num += inventory.CountItems(name, quality, matchWorldLevel);
			}
		}
		CountMemo[key] = num;
		return num;
	}

	public static bool Have(string name, bool matchWorldLevel)
	{
		foreach (Container container in GetContainers())
		{
			Inventory inventory = container.GetInventory();
			if (inventory != null && inventory.HaveItem(name, matchWorldLevel))
			{
				return true;
			}
		}
		return false;
	}

	public static int Remove(string name, int amount, int itemQuality, bool worldLevelBased)
	{
		return Remove(GetContainers(), name, amount, itemQuality, worldLevelBased);
	}

	public static int Remove(List<Container> containers, string name, int amount, int itemQuality, bool worldLevelBased, int keepPerContainer = 0)
	{
		int num = amount;
		foreach (Container container in containers)
		{
			if (num <= 0)
			{
				break;
			}
			if ((Object)(object)container == (Object)null)
			{
				continue;
			}
			Inventory inventory = container.GetInventory();
			if (inventory != null)
			{
				int num2 = inventory.CountItems(name, itemQuality, worldLevelBased);
				int num3 = num2 - Math.Max(0, keepPerContainer);
				if (num3 > 0 && ClaimOwnership(container))
				{
					int num4 = Math.Min(num3, num);
					inventory.RemoveItem(name, num4, itemQuality, worldLevelBased);
					int val = num2 - inventory.CountItems(name, itemQuality, worldLevelBased);
					num -= Math.Max(0, val);
				}
			}
		}
		CountMemo.Clear();
		StorageStock.Invalidate();
		return amount - num;
	}

	public static bool ClaimOwnership(Container c)
	{
		ZNetView val = ContainerNView.Invoke(c);
		if ((Object)(object)val == (Object)null || !val.IsValid())
		{
			return false;
		}
		if (!val.IsOwner())
		{
			val.ClaimOwnership();
		}
		return val.IsOwner();
	}

	public static List<Container> FindAround(Vector3 origin, float radius)
	{
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		List<Container> list = new List<Container>();
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return list;
		}
		long playerID = localPlayer.GetPlayerID();
		Container openContainer = (((Object)(object)InventoryGui.instance != (Object)null) ? GuiCurrentContainer.Invoke(InventoryGui.instance) : null);
		List<KeyValuePair<float, Container>> list2 = new List<KeyValuePair<float, Container>>();
		Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
		foreach (Container val in array)
		{
			try
			{
				if (!((Object)(object)val == (Object)null) && ((Behaviour)val).isActiveAndEnabled)
				{
					float num = Vector3.Distance(origin, ((Component)val).transform.position);
					if (!(num > radius) && IsUsable(val, playerID, openContainer))
					{
						list2.Add(new KeyValuePair<float, Container>(num, val));
					}
				}
			}
			catch (Exception ex)
			{
				KMartBoysPlugin.LogOnce("containersource2", "Skipped a container while scanning: " + ex.Message);
			}
		}
		list2.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key));
		foreach (KeyValuePair<float, Container> item in list2)
		{
			list.Add(item.Value);
		}
		return list;
	}
}
internal static class CraftScope
{
	public static int CountDepth;

	public static int ConsumeDepth;

	public static bool CraftingEnabled
	{
		get
		{
			if (KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.CraftEnabled.Value)
			{
				return !KMartBoysPlugin.OtherCraftModLoaded;
			}
			return false;
		}
	}

	public static bool BuildingEnabled
	{
		get
		{
			if (CraftingEnabled)
			{
				return KMartBoysPlugin.CraftAllowBuilding.Value;
			}
			return false;
		}
	}

	public static bool IsLocalPlayer(Player p)
	{
		if ((Object)(object)p != (Object)null)
		{
			return (Object)(object)p == (Object)(object)Player.m_localPlayer;
		}
		return false;
	}

	public static bool IsLocalInventory(Inventory inv)
	{
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null && inv != null)
		{
			return inv == ((Humanoid)localPlayer).GetInventory();
		}
		return false;
	}
}
[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
internal static class Player_HaveRequirementItems_Patch
{
	private static void Prefix(Player __instance, bool discover, out bool __state)
	{
		__state = !discover && CraftScope.CraftingEnabled && CraftScope.IsLocalPlayer(__instance);
		if (__state)
		{
			CraftScope.CountDepth++;
		}
	}

	private static Exception Finalizer(Exception __exception, bool __state)
	{
		if (__state)
		{
			CraftScope.CountDepth--;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
{
	typeof(Piece),
	typeof(RequirementMode)
})]
internal static class Player_HaveRequirementsPiece_Patch
{
	private static void Prefix(Player __instance, RequirementMode mode, out bool __state)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Invalid comparison between Unknown and I4
		__state = (int)mode != 1 && CraftScope.BuildingEnabled && CraftScope.IsLocalPlayer(__instance);
		if (__state)
		{
			CraftScope.CountDepth++;
		}
	}

	private static Exception Finalizer(Exception __exception, bool __state)
	{
		if (__state)
		{
			CraftScope.CountDepth--;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
internal static class InventoryGui_SetupRequirement_Color_Patch
{
	private static void Prefix(Player player, bool craft, out bool __state)
	{
		__state = KMartBoysPlugin.CraftFixColors.Value && (craft ? CraftScope.CraftingEnabled : CraftScope.BuildingEnabled) && CraftScope.IsLocalPlayer(player);
		if (__state)
		{
			CraftScope.CountDepth++;
		}
	}

	private static Exception Finalizer(Exception __exception, bool __state)
	{
		if (__state)
		{
			CraftScope.CountDepth--;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(Inventory), "CountItems")]
internal static class Inventory_CountItems_Patch
{
	private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
	{
		if (CraftScope.CountDepth <= 0 || CraftScope.ConsumeDepth > 0 || !CraftScope.IsLocalInventory(__instance))
		{
			return;
		}
		try
		{
			__result += ContainerSource.Count(name, quality, matchWorldLevel);
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("countitems", "Counting container items failed: " + ex.Message);
		}
	}
}
[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
{
	typeof(string),
	typeof(bool)
})]
internal static class Inventory_HaveItem_Patch
{
	private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
	{
		if (__result || CraftScope.CountDepth <= 0 || CraftScope.ConsumeDepth > 0 || !CraftScope.IsLocalInventory(__instance))
		{
			return;
		}
		try
		{
			__result = ContainerSource.Have(name, matchWorldLevel);
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("haveitem", "Checking container items failed: " + ex.Message);
		}
	}
}
[HarmonyPatch(typeof(Player), "ConsumeResources")]
internal static class Player_ConsumeResources_Patch
{
	private static void Prefix(Player __instance, out bool __state)
	{
		__state = CraftScope.CraftingEnabled && CraftScope.IsLocalPlayer(__instance);
		if (__state)
		{
			CraftScope.ConsumeDepth++;
		}
	}

	private static Exception Finalizer(Exception __exception, bool __state)
	{
		if (__state)
		{
			CraftScope.ConsumeDepth--;
		}
		return __exception;
	}
}
[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
{
	typeof(string),
	typeof(int),
	typeof(int),
	typeof(bool)
})]
internal static class Inventory_RemoveItemByName_Patch
{
	private static void Prefix(Inventory __instance, string name, ref int amount, int itemQuality, bool worldLevelBased)
	{
		if (CraftScope.ConsumeDepth <= 0 || amount <= 0 || !CraftScope.IsLocalInventory(__instance))
		{
			return;
		}
		try
		{
			int num = __instance.CountItems(name, itemQuality, worldLevelBased);
			if (num < amount)
			{
				int num2 = amount - num;
				int num3 = ContainerSource.Remove(name, num2, itemQuality, worldLevelBased);
				if (num3 < num2)
				{
					KMartBoysPlugin.LogOnce("consumeshort", "Containers had " + (num2 - num3) + " fewer " + name + " than expected while crafting/building.");
				}
				amount = num;
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("consume", "Taking materials from containers failed: " + ex.Message);
		}
	}
}
public enum StockDisplayMode
{
	InSlotNumber,
	LineBelowSlot
}
internal static class StorageStock
{
	private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

	private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

	private static readonly Dictionary<string, int> Counts = new Dictionary<string, int>();

	private static float _lastScan = -999f;

	private static int _containersCounted;

	public static int ContainersCounted => _containersCounted;

	public static int Get(string itemName)
	{
		if (string.IsNullOrEmpty(itemName))
		{
			return 0;
		}
		float num = Mathf.Max(0.25f, KMartBoysPlugin.StockRefreshSeconds.Value);
		if (Time.unscaledTime - _lastScan >= num)
		{
			Rescan();
		}
		if (!Counts.TryGetValue(itemName, out var value))
		{
			return 0;
		}
		return value;
	}

	public static void Invalidate()
	{
		_lastScan = -999f;
	}

	private static void Rescan()
	{
		//IL_0030: 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_008b: 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_013a: Unknown result type (might be due to invalid IL or missing references)
		_lastScan = Time.unscaledTime;
		Counts.Clear();
		_containersCounted = 0;
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		Vector3 position = ((Component)localPlayer).transform.position;
		float value = KMartBoysPlugin.StockRadius.Value;
		bool value2 = KMartBoysPlugin.StockOnlyAccessible.Value;
		long playerID = localPlayer.GetPlayerID();
		Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
		foreach (Container val in array)
		{
			try
			{
				if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || (value > 0f && Vector3.Distance(position, ((Component)val).transform.position) > value))
				{
					continue;
				}
				ZNetView val2 = ContainerNView.Invoke(val);
				if ((Object)(object)val2 == (Object)null || !val2.IsValid())
				{
					continue;
				}
				Inventory inventory = val.GetInventory();
				if (inventory == null || (Object)(object)((Component)val).GetComponentInParent<TombStone>() != (Object)null || (value2 && ((ContainerCheckAccess != null && !(bool)ContainerCheckAccess.Invoke(val, new object[1] { playerID })) || (val.m_checkGuardStone && !PrivateArea.CheckAccess(((Component)val).transform.position, 0f, false, false)))))
				{
					continue;
				}
				_containersCounted++;
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (allItem != null && allItem.m_shared != null)
					{
						string name = allItem.m_shared.m_name;
						Counts.TryGetValue(name, out var value3);
						Counts[name] = value3 + allItem.m_stack;
					}
				}
			}
			catch (Exception ex)
			{
				KMartBoysPlugin.LogOnce("stockscan", "Storage scan skipped a container: " + ex.Message);
			}
		}
	}

	public static int CountInInventory(Player player, string itemName)
	{
		if ((Object)(object)player == (Object)null)
		{
			return 0;
		}
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return 0;
		}
		int num = 0;
		foreach (ItemData allItem in inventory.GetAllItems())
		{
			if (allItem != null && allItem.m_shared != null && allItem.m_shared.m_name == itemName)
			{
				num += allItem.m_stack;
			}
		}
		return num;
	}
}
[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
internal static class InventoryGui_SetupRequirement_Patch
{
	private const string LabelName = "KMartBoys_Stock";

	private static bool _loggedLayout;

	private static void Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result)
	{
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0177: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			bool num = __result && KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.StockEnabled.Value && (craft || KMartBoysPlugin.StockInBuildMenu.Value) && (Object)(object)elementRoot != (Object)null && req != null && (Object)(object)req.m_resItem != (Object)null && (Object)(object)player != (Object)null;
			TMP_Text val = FindLabel(elementRoot);
			bool flag = KMartBoysPlugin.StockDisplay.Value == StockDisplayMode.LineBelowSlot;
			if ((!num || !flag) && (Object)(object)val != (Object)null)
			{
				((Component)val).gameObject.SetActive(false);
			}
			if (!num)
			{
				return;
			}
			TMP_Text val2 = FindAmountText(elementRoot);
			string name = req.m_resItem.m_itemData.m_shared.m_name;
			int num2 = ReadNeed(val2, req, quality, craftMultiplier);
			int num3 = StorageStock.CountInInventory(player, name);
			int num4 = StorageStock.Get(name);
			int num5 = num3 + num4;
			if (!flag)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.text = Format(KMartBoysPlugin.StockAmountFormat.Value, num2, num3, num4, num5);
					val2.overflowMode = (TextOverflowModes)0;
				}
				return;
			}
			if ((Object)(object)val == (Object)null)
			{
				val = CreateLabel(elementRoot, val2);
			}
			if (!((Object)(object)val == (Object)null))
			{
				LogLayoutOnce(elementRoot);
				val.text = Format(KMartBoysPlugin.StockFormat.Value, num2, num3, num4, num5);
				((Graphic)val).color = ((num5 >= num2) ? KMartBoysPlugin.StockEnoughColor.Value : KMartBoysPlugin.StockShortColor.Value);
				val.fontSize = KMartBoysPlugin.StockFontSize.Value;
				((RectTransform)val.transform).anchoredPosition = new Vector2(KMartBoysPlugin.StockOffsetX.Value, KMartBoysPlugin.StockOffsetY.Value);
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("stockui", "Crafting stock display error: " + ex);
		}
	}

	internal static TMP_Text FindLabel(Transform elementRoot)
	{
		if ((Object)(object)elementRoot == (Object)null)
		{
			return null;
		}
		Transform val = elementRoot.Find("KMartBoys_Stock");
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return ((Component)val).GetComponent<TMP_Text>();
	}

	private static TMP_Text FindAmountText(Transform elementRoot)
	{
		Transform val = elementRoot.Find("res_amount");
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return ((Component)val).GetComponent<TMP_Text>();
	}

	private static TMP_Text CreateLabel(Transform elementRoot, TMP_Text template)
	{
		//IL_007b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Expected O, but got Unknown
		//IL_008c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		GameObject val;
		if ((Object)(object)template != (Object)null)
		{
			val = Object.Instantiate<GameObject>(((Component)template).gameObject, elementRoot, false);
			for (int num = val.transform.childCount - 1; num >= 0; num--)
			{
				Object.Destroy((Object)(object)((Component)val.transform.GetChild(num)).gameObject);
			}
		}
		else
		{
			val = ((Component)ClockHud.CreateHudText("KMartBoys_Stock", elementRoot)).gameObject;
		}
		((Object)val).name = "KMartBoys_Stock";
		TMP_Text component = val.GetComponent<TMP_Text>();
		if ((Object)(object)component == (Object)null)
		{
			return null;
		}
		RectTransform val2 = (RectTransform)val.transform;
		val2.anchorMin = new Vector2(0.5f, 0f);
		val2.anchorMax = new Vector2(0.5f, 0f);
		val2.pivot = new Vector2(0.5f, 1f);
		val2.sizeDelta = new Vector2(120f, 40f);
		((Transform)val2).localScale = Vector3.one;
		((Transform)val2).localRotation = Quaternion.identity;
		component.alignment = (TextAlignmentOptions)258;
		component.overflowMode = (TextOverflowModes)0;
		component.richText = true;
		((Graphic)component).raycastTarget = false;
		component.enableAutoSizing = false;
		SetNoWrap(component);
		((Transform)val2).SetAsLastSibling();
		return component;
	}

	private static void SetNoWrap(TMP_Text text)
	{
		try
		{
			PropertyInfo property = typeof(TMP_Text).GetProperty("textWrappingMode");
			if (property != null && property.PropertyType.IsEnum)
			{
				property.SetValue(text, Enum.ToObject(property.PropertyType, 0), null);
				return;
			}
			PropertyInfo property2 = typeof(TMP_Text).GetProperty("enableWordWrapping");
			if (property2 != null)
			{
				property2.SetValue(text, false, null);
			}
		}
		catch
		{
		}
	}

	private static int ReadNeed(TMP_Text amountText, Requirement req, int quality, int craftMultiplier)
	{
		if ((Object)(object)amountText != (Object)null && amountText.text != null && amountText.text.IndexOf('/') < 0 && int.TryParse(StripTags(amountText.text), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
		{
			return result;
		}
		return req.GetAmount(quality) * Math.Max(1, craftMultiplier);
	}

	private static string StripTags(string s)
	{
		if (string.IsNullOrEmpty(s))
		{
			return s;
		}
		StringBuilder stringBuilder = new StringBuilder(s.Length);
		bool flag = false;
		foreach (char c in s)
		{
			switch (c)
			{
			case '<':
				flag = true;
				continue;
			case '>':
				flag = false;
				continue;
			}
			if (!flag)
			{
				stringBuilder.Append(c);
			}
		}
		return stringBuilder.ToString().Trim();
	}

	private static string Format(string template, int need, int have, int stored, int total)
	{
		if (string.IsNullOrEmpty(template))
		{
			return string.Empty;
		}
		return template.Replace("\\n", "\n").Replace("{need}", need.ToString()).Replace("{have}", have.ToString())
			.Replace("{stored}", stored.ToString())
			.Replace("{total}", total.ToString())
			.Replace("{missing}", Math.Max(0, need - total).ToString());
	}

	private static void LogLayoutOnce(Transform elementRoot)
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: 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_00ba: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
		if (_loggedLayout)
		{
			return;
		}
		_loggedLayout = true;
		try
		{
			StringBuilder stringBuilder = new StringBuilder("Requirement slot layout: ");
			stringBuilder.Append(Path(elementRoot));
			RectTransform val = (RectTransform)(object)((elementRoot is RectTransform) ? elementRoot : null);
			Rect rect;
			if ((Object)(object)val != (Object)null)
			{
				StringBuilder stringBuilder2 = stringBuilder.Append(" size=");
				rect = val.rect;
				stringBuilder2.Append(((Rect)(ref rect)).size);
			}
			for (int i = 0; i < elementRoot.childCount; i++)
			{
				Transform child = elementRoot.GetChild(i);
				RectTransform val2 = (RectTransform)(object)((child is RectTransform) ? child : null);
				stringBuilder.Append(" | ").Append(((Object)child).name);
				if ((Object)(object)val2 != (Object)null)
				{
					StringBuilder stringBuilder3 = stringBuilder.Append(" pos=").Append(val2.anchoredPosition).Append(" size=");
					rect = val2.rect;
					stringBuilder3.Append(((Rect)(ref rect)).size);
				}
			}
			KMartBoysPlugin.Log(stringBuilder.ToString());
		}
		catch
		{
		}
	}

	private static string Path(Transform t)
	{
		string text = ((Object)t).name;
		int num = 0;
		while ((Object)(object)t.parent != (Object)null && num++ < 4)
		{
			t = t.parent;
			text = ((Object)t).name + "/" + text;
		}
		return text;
	}
}
[HarmonyPatch(typeof(InventoryGui), "HideRequirement")]
internal static class InventoryGui_HideRequirement_Patch
{
	private static void Postfix(Transform elementRoot)
	{
		TMP_Text val = InventoryGui_SetupRequirement_Patch.FindLabel(elementRoot);
		if ((Object)(object)val != (Object)null)
		{
			((Component)val).gameObject.SetActive(false);
		}
	}
}
public enum DeathChatChannel
{
	Shout,
	Normal
}
[HarmonyPatch(typeof(Player), "OnDeath")]
internal static class Player_OnDeath_Patch
{
	private static float _lastSent = -999f;

	private static void Prefix(Player __instance)
	{
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.DeathMessageEnabled.Value && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)Chat.instance == (Object)null) && !(Time.unscaledTime - _lastSent < 3f))
			{
				_lastSent = Time.unscaledTime;
				string text = Pick(KMartBoysPlugin.DeathMessages.Value);
				if (!string.IsNullOrEmpty(text))
				{
					text = text.Replace("{name}", __instance.GetPlayerName());
					Type val = (Type)((KMartBoysPlugin.DeathMessageChannel.Value == DeathChatChannel.Normal) ? 1 : 2);
					Chat.instance.SendText(val, text);
				}
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("deathmsg", "Death message failed: " + ex.Message);
		}
	}

	private static string Pick(string raw)
	{
		if (string.IsNullOrEmpty(raw))
		{
			return null;
		}
		string[] array = raw.Split('|');
		int num = array.Length;
		while (num-- > 0)
		{
			string text = array[Random.Range(0, array.Length)].Trim();
			if (text.Length > 0)
			{
				return text;
			}
		}
		return null;
	}
}
internal static class Depositor
{
	private static readonly FieldRef<Container, ZNetView> ContainerNView = AccessTools.FieldRefAccess<Container, ZNetView>("m_nview");

	private static readonly FieldRef<InventoryGui, Container> GuiCurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

	private static readonly FieldRef<InventoryGui, ItemData> GuiDragItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem");

	private static readonly MethodInfo ContainerCheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null);

	public static void DepositNearby(Player player)
	{
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return;
		}
		List<Container> list = FindContainers(player);
		if (list.Count == 0)
		{
			Notify(player, KMartBoysPlugin.NoContainersMessage.Value, 0, 0);
			return;
		}
		ItemData dragItem = null;
		if ((Object)(object)InventoryGui.instance != (Object)null)
		{
			dragItem = GuiDragItem.Invoke(InventoryGui.instance);
		}
		HashSet<long> locks = SlotLocks.GetLocks(player);
		List<ItemData> list2 = new List<ItemData>(inventory.GetAllItems());
		int num = 0;
		HashSet<Container> hashSet = new HashSet<Container>();
		foreach (ItemData item in list2)
		{
			if (!ShouldDeposit(item, dragItem, locks))
			{
				continue;
			}
			foreach (Container item2 in list)
			{
				if (!inventory.ContainsItem(item))
				{
					break;
				}
				Inventory inventory2 = item2.GetInventory();
				if (inventory2.ContainsItemByName(item.m_shared.m_name) && EnsureOwnership(item2))
				{
					int num2 = MoveInto(inventory, inventory2, item);
					if (num2 > 0)
					{
						num += num2;
						hashSet.Add(item2);
					}
				}
			}
		}
		if (num > 0)
		{
			StorageStock.Invalidate();
			if (KMartBoysPlugin.CenterMessageEnabled.Value)
			{
				string text = Format(PickTier(num), num, hashSet.Count);
				if (!string.IsNullOrEmpty(text))
				{
					((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
				}
			}
			Notify(player, KMartBoysPlugin.SummaryMessage.Value, num, hashSet.Count);
		}
		else
		{
			Notify(player, KMartBoysPlugin.NothingToDepositMessage.Value, 0, 0);
		}
	}

	private static bool ShouldDeposit(ItemData item, ItemData dragItem, HashSet<long> lockedSlots)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Invalid comparison between Unknown and I4
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		if (item == null || item.m_shared == null)
		{
			return false;
		}
		if (item == dragItem)
		{
			return false;
		}
		if (KMartBoysPlugin.IgnoreEquipped.Value && item.m_equipped)
		{
			return false;
		}
		if (KMartBoysPlugin.IgnoreHotbar.Value && item.m_gridPos.y == 0)
		{
			return false;
		}
		if (KMartBoysPlugin.IgnoreAmmo.Value && (int)item.m_shared.m_itemType == 9)
		{
			return false;
		}
		if (ModCompat.IsSpecialSlot(item.m_gridPos))
		{
			return false;
		}
		if (KMartBoysPlugin.SlotLockEnabled.Value && lockedSlots.Contains(SlotLocks.Key(item.m_gridPos)))
		{
			return false;
		}
		if (!KMartBoysPlugin.DepositNonStackables.Value && item.m_shared.m_maxStackSize <= 1)
		{
			return false;
		}
		return true;
	}

	private static List<Container> FindContainers(Player player)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0127: Unknown result type (might be due to invalid IL or missing references)
		float value = KMartBoysPlugin.Radius.Value;
		Vector3 position = ((Component)player).transform.position;
		long playerID = player.GetPlayerID();
		Container val = (((Object)(object)InventoryGui.instance != (Object)null) ? GuiCurrentContainer.Invoke(InventoryGui.instance) : null);
		List<KeyValuePair<float, Container>> list = new List<KeyValuePair<float, Container>>();
		Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
		foreach (Container val2 in array)
		{
			if ((Object)(object)val2 == (Object)null || !((Behaviour)val2).isActiveAndEnabled)
			{
				continue;
			}
			float num = Vector3.Distance(position, ((Component)val2).transform.position);
			if (!(num > value))
			{
				ZNetView val3 = ContainerNView.Invoke(val2);
				if (!((Object)(object)val3 == (Object)null) && val3.IsValid() && val2.GetInventory() != null && !((Object)(object)((Component)val2).GetComponentInParent<TombStone>() != (Object)null) && (!val2.IsInUse() || !((Object)(object)val2 != (Object)(object)val)) && (!(ContainerCheckAccess != null) || (bool)ContainerCheckAccess.Invoke(val2, new object[1] { playerID })) && (!val2.m_checkGuardStone || PrivateArea.CheckAccess(((Component)val2).transform.position, 0f, false, false)))
				{
					list.Add(new KeyValuePair<float, Container>(num, val2));
				}
			}
		}
		list.Sort((KeyValuePair<float, Container> a, KeyValuePair<float, Container> b) => a.Key.CompareTo(b.Key));
		List<Container> list2 = new List<Container>(list.Count);
		foreach (KeyValuePair<float, Container> item in list)
		{
			list2.Add(item.Value);
		}
		return list2;
	}

	private static bool EnsureOwnership(Container c)
	{
		ZNetView val = ContainerNView.Invoke(c);
		if ((Object)(object)val == (Object)null || !val.IsValid())
		{
			return false;
		}
		if (!val.IsOwner())
		{
			val.ClaimOwnership();
		}
		return val.IsOwner();
	}

	private static bool SameStack(ItemData a, ItemData b)
	{
		if (a.m_shared.m_name == b.m_shared.m_name && a.m_quality == b.m_quality)
		{
			return a.m_worldLevel == b.m_worldLevel;
		}
		return false;
	}

	private static int MoveInto(Inventory from, Inventory target, ItemData item)
	{
		int num = Math.Max(1, item.m_shared.m_maxStackSize);
		int num2 = 0;
		if (num > 1)
		{
			foreach (ItemData item2 in new List<ItemData>(target.GetAllItems()))
			{
				if (!from.ContainsItem(item))
				{
					return num2;
				}
				if (SameStack(item2, item) && item2.m_stack < num)
				{
					int amount = Math.Min(item.m_stack, num - item2.m_stack);
					num2 += MoveSlot(from, target, item, amount, item2.m_gridPos.x, item2.m_gridPos.y);
				}
			}
		}
		int width = target.GetWidth();
		int height = target.GetHeight();
		for (int i = 0; i < height; i++)
		{
			for (int j = 0; j < width; j++)
			{
				if (!from.ContainsItem(item))
				{
					return num2;
				}
				if (target.GetItemAt(j, i) == null)
				{
					int amount2 = Math.Min(item.m_stack, num);
					num2 += MoveSlot(from, target, item, amount2, j, i);
				}
			}
		}
		return num2;
	}

	private static int MoveSlot(Inventory from, Inventory target, ItemData item, int amount, int x, int y)
	{
		if (amount <= 0)
		{
			return 0;
		}
		int stack = item.m_stack;
		target.MoveItemToThis(from, item, amount, x, y);
		int num = (from.ContainsItem(item) ? item.m_stack : 0);
		return Math.Max(0, stack - num);
	}

	private static string PickTier(int items)
	{
		string result = null;
		int num = -1;
		for (int i = 0; i < KMartBoysPlugin.TierMinItems.Length; i++)
		{
			int value = KMartBoysPlugin.TierMinItems[i].Value;
			string value2 = KMartBoysPlugin.TierMessages[i].Value;
			if (value > 0 && !string.IsNullOrEmpty(value2) && items >= value && value > num)
			{
				num = value;
				result = value2;
			}
		}
		return result;
	}

	private static string Format(string template, int items, int containers)
	{
		if (string.IsNullOrEmpty(template))
		{
			return template;
		}
		return template.Replace("{items}", items.ToString()).Replace("{containers}", containers.ToString()).Replace("{itemsWord}", (items == 1) ? "item" : "items")
			.Replace("{containersWord}", (containers == 1) ? "container" : "containers");
	}

	private static void Notify(Player player, string template, int items, int containers)
	{
		if (KMartBoysPlugin.SummaryMessageEnabled.Value)
		{
			string text = Format(template, items, containers);
			if (!string.IsNullOrEmpty(text))
			{
				((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}
	}
}
public enum SortMode
{
	Name,
	Type,
	Value,
	Quality,
	Power,
	Weight
}
internal static class InventorySorter
{
	private static readonly MethodInfo InventoryChanged = AccessTools.Method(typeof(Inventory), "Changed", new Type[2]
	{
		typeof(bool),
		typeof(bool)
	}, (Type[])null);

	public static void Sort(Inventory inv, bool isPlayer)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: 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_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: Unknown result type (might be due to invalid IL or missing references)
		if (inv == null)
		{
			return;
		}
		Player player = Player.m_localPlayer;
		Func<Vector2i, bool> func = delegate(Vector2i pos)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!isPlayer)
			{
				return false;
			}
			if (KMartBoysPlugin.SortSkipHotbar.Value && pos.y == 0)
			{
				return true;
			}
			if (ModCompat.IsSpecialSlot(pos))
			{
				return true;
			}
			return ((Object)(object)player != (Object)null && KMartBoysPlugin.SlotLockEnabled.Value && SlotLocks.IsLocked(player, pos)) ? true : false;
		};
		ItemData val = null;
		if ((Object)(object)InventoryGui.instance != (Object)null)
		{
			val = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_dragItem").Invoke(InventoryGui.instance);
		}
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData allItem in inv.GetAllItems())
		{
			if (allItem != null && allItem != val && !func(allItem.m_gridPos))
			{
				list.Add(allItem);
			}
		}
		if (list.Count == 0)
		{
			return;
		}
		if (KMartBoysPlugin.SortMergeStacks.Value)
		{
			MergeStacks(inv, list);
		}
		list.Sort(Comparer(KMartBoysPlugin.SortModeSetting.Value));
		List<Vector2i> list2 = new List<Vector2i>();
		HashSet<long> hashSet = new HashSet<long>();
		foreach (ItemData allItem2 in inv.GetAllItems())
		{
			if (allItem2 != null && !list.Contains(allItem2))
			{
				hashSet.Add(SlotLocks.Key(allItem2.m_gridPos));
			}
		}
		Vector2i val2 = default(Vector2i);
		for (int num = 0; num < inv.GetHeight(); num++)
		{
			for (int num2 = 0; num2 < inv.GetWidth(); num2++)
			{
				((Vector2i)(ref val2))..ctor(num2, num);
				if (!func(val2) && !hashSet.Contains(SlotLocks.Key(val2)))
				{
					list2.Add(val2);
				}
			}
		}
		if (list2.Count >= list.Count)
		{
			for (int num3 = 0; num3 < list.Count; num3++)
			{
				list[num3].m_gridPos = list2[num3];
			}
			if (InventoryChanged != null)
			{
				InventoryChanged.Invoke(inv, new object[2] { false, false });
			}
		}
	}

	private static void MergeStacks(Inventory inv, List<ItemData> items)
	{
		Dictionary<string, ItemData> dictionary = new Dictionary<string, ItemData>();
		List<ItemData> list = new List<ItemData>();
		foreach (ItemData item in items)
		{
			int maxStackSize = item.m_shared.m_maxStackSize;
			if (maxStackSize <= 1 || item.m_equipped)
			{
				continue;
			}
			string key = item.m_shared.m_name + "|" + item.m_quality + "|" + item.m_worldLevel;
			if (dictionary.TryGetValue(key, out var value) && value.m_stack < maxStackSize)
			{
				int num = Math.Min(maxStackSize - value.m_stack, item.m_stack);
				ItemData obj = value;
				obj.m_stack += num;
				item.m_stack -= num;
				if (item.m_stack <= 0)
				{
					list.Add(item);
					continue;
				}
			}
			if (item.m_stack < maxStackSize)
			{
				dictionary[key] = item;
			}
			else
			{
				dictionary.Remove(key);
			}
		}
		foreach (ItemData item2 in list)
		{
			items.Remove(item2);
			inv.RemoveItem(item2);
		}
	}

	private static string DisplayName(ItemData item)
	{
		string name = item.m_shared.m_name;
		if (Localization.instance == null)
		{
			return name;
		}
		return Localization.instance.Localize(name);
	}

	private static float Power(ItemData item)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		try
		{
			float val = num;
			DamageTypes damage = item.GetDamage();
			num = Math.Max(val, ((DamageTypes)(ref damage)).GetTotalDamage());
			num = Math.Max(num, item.GetArmor());
			num = Math.Max(num, item.GetBaseBlockPower());
		}
		catch
		{
		}
		return num;
	}

	private static int TypeOrder(ItemData item)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Expected I4, but got Unknown
		ItemType itemType = item.m_shared.m_itemType;
		switch (itemType - 1)
		{
		case 2:
		case 3:
		case 13:
		case 19:
		case 21:
			return 0;
		case 8:
		case 22:
			return 1;
		case 4:
			return 2;
		case 5:
		case 6:
		case 10:
		case 11:
		case 16:
			return 3;
		case 17:
		case 23:
			return 4;
		case 14:
		case 18:
			return 5;
		case 1:
			return 6;
		case 20:
			return 7;
		case 0:
			return 8;
		case 12:
			return 9;
		default:
			return 10;
		}
	}

	private static Comparison<ItemData> Comparer(SortMode mode)
	{
		Comparison<ItemData> byName = delegate(ItemData a, ItemData b)
		{
			int num = string.Compare(DisplayName(a), DisplayName(b), StringComparison.CurrentCultureIgnoreCase);
			if (num != 0)
			{
				return num;
			}
			num = b.m_quality.CompareTo(a.m_quality);
			return (num == 0) ? b.m_stack.CompareTo(a.m_stack) : num;
		};
		return mode switch
		{
			SortMode.Type => delegate(ItemData a, ItemData b)
			{
				int num = TypeOrder(a).CompareTo(TypeOrder(b));
				return (num == 0) ? byName(a, b) : num;
			}, 
			SortMode.Value => delegate(ItemData a, ItemData b)
			{
				int num = ((long)b.m_shared.m_value * (long)b.m_stack).CompareTo((long)a.m_shared.m_value * (long)a.m_stack);
				return (num == 0) ? byName(a, b) : num;
			}, 
			SortMode.Quality => delegate(ItemData a, ItemData b)
			{
				int num = b.m_quality.CompareTo(a.m_quality);
				return (num == 0) ? byName(a, b) : num;
			}, 
			SortMode.Power => delegate(ItemData a, ItemData b)
			{
				int num = Power(b).CompareTo(Power(a));
				return (num == 0) ? byName(a, b) : num;
			}, 
			SortMode.Weight => delegate(ItemData a, ItemData b)
			{
				int num = (b.m_shared.m_weight * (float)b.m_stack).CompareTo(a.m_shared.m_weight * (float)a.m_stack);
				return (num == 0) ? byName(a, b) : num;
			}, 
			_ => byName, 
		};
	}
}
internal class SortButtonClick : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
{
	public bool ForPlayer;

	public void OnPointerClick(PointerEventData e)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Invalid comparison between Unknown and I4
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((int)e.button == 1)
			{
				int length = Enum.GetValues(typeof(SortMode)).Length;
				KMartBoysPlugin.SortModeSetting.Value = (SortMode)((int)(KMartBoysPlugin.SortModeSetting.Value + 1) % length);
				SortButtons.RefreshLabels();
			}
			else
			{
				if ((int)e.button != 0)
				{
					return;
				}
				Inventory inv = null;
				if (ForPlayer)
				{
					if ((Object)(object)Player.m_localPlayer != (Object)null)
					{
						inv = ((Humanoid)Player.m_localPlayer).GetInventory();
					}
				}
				else
				{
					Container val = SortButtons.OpenContainer();
					if ((Object)(object)val != (Object)null)
					{
						ContainerSource.ClaimOwnership(val);
						inv = val.GetInventory();
					}
				}
				InventorySorter.Sort(inv, ForPlayer);
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("sortclick", "Sorting failed: " + ex);
		}
	}
}
internal static class SortButtons
{
	private const string PlayerButtonName = "KMartBoys_SortPlayer";

	private const string ContainerButtonName = "KMartBoys_SortContainer";

	private static readonly FieldRef<InventoryGui, Container> CurrentContainer = AccessTools.FieldRefAccess<InventoryGui, Container>("m_currentContainer");

	private static GameObject _playerButton;

	private static GameObject _containerButton;

	public static Container OpenContainer()
	{
		if (!((Object)(object)InventoryGui.instance != (Object)null))
		{
			return null;
		}
		return CurrentContainer.Invoke(InventoryGui.instance);
	}

	public static void Ensure(InventoryGui gui)
	{
		bool flag = KMartBoysPlugin.ModEnabled.Value && KMartBoysPlugin.SortEnabled.Value;
		if (!((Object)(object)gui == (Object)null) && !((Object)(object)gui.m_takeAllButton == (Object)null))
		{
			if (flag && (Object)(object)_playerButton == (Object)null && (Object)(object)gui.m_player != (Object)null)
			{
				_playerButton = Create(gui, gui.m_player, "KMartBoys_SortPlayer", forPlayer: true);
			}
			if (flag && (Object)(object)_containerButton == (Object)null && (Object)(object)gui.m_container != (Object)null)
			{
				_containerButton = Create(gui, gui.m_container, "KMartBoys_SortContainer", forPlayer: false);
			}
			if ((Object)(object)_playerButton != (Object)null)
			{
				_playerButton.SetActive(flag);
				Place(_playerButton, forPlayer: true);
			}
			if ((Object)(object)_containerButton != (Object)null)
			{
				_containerButton.SetActive(flag);
				Place(_containerButton, forPlayer: false);
			}
			RefreshLabels();
		}
	}

	private static GameObject Create(InventoryGui gui, RectTransform parent, string name, bool forPlayer)
	{
		//IL_009f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Expected O, but got Unknown
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0086: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)parent, false);
		((Object)val).name = name;
		MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val2 in componentsInChildren)
		{
			string name2 = ((object)val2).GetType().Name;
			if (name2 == "Localize" || name2 == "UIGamePad")
			{
				Object.DestroyImmediate((Object)(object)val2);
			}
		}
		Button component = val.GetComponent<Button>();
		if ((Object)(object)component != (Object)null)
		{
			component.onClick = new ButtonClickedEvent();
			((Selectable)component).interactable = true;
		}
		val.AddComponent<SortButtonClick>().ForPlayer = forPlayer;
		RectTransform val3 = (RectTransform)val.transform;
		val3.sizeDelta = new Vector2(140f, (val3.sizeDelta.y > 0f) ? val3.sizeDelta.y : 32f);
		return val;
	}

	private static void Place(GameObject go, bool forPlayer)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = (RectTransform)go.transform;
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(1f, 1f);
		val.anchorMax = val2;
		val.anchorMin = val2;
		val.pivot = new Vector2(1f, 0f);
		Vector2 anchoredPosition = (forPlayer ? new Vector2(KMartBoysPlugin.SortPlayerOffsetX.Value, KMartBoysPlugin.SortPlayerOffsetY.Value) : new Vector2(KMartBoysPlugin.SortChestOffsetX.Value, KMartBoysPlugin.SortChestOffsetY.Value));
		val.anchoredPosition = anchoredPosition;
	}

	public static void RefreshLabels()
	{
		string text = "Sort: " + KMartBoysPlugin.SortModeSetting.Value;
		SetLabel(_playerButton, text);
		SetLabel(_containerButton, text);
	}

	private static void SetLabel(GameObject go, string text)
	{
		if (!((Object)(object)go == (Object)null))
		{
			TMP_Text componentInChildren = go.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
			}
		}
	}
}
[HarmonyPatch(typeof(InventoryGui), "Show")]
internal static class InventoryGui_Show_SortButtons_Patch
{
	private static void Postfix(InventoryGui __instance)
	{
		try
		{
			SortButtons.Ensure(__instance);
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("sortbuttons", "Creating sort buttons failed: " + ex);
		}
	}
}
internal static class ModCompat
{
	private static bool _resolved;

	private static MethodInfo _eaqsIsSlotCell;

	private static void Resolve()
	{
		if (_resolved)
		{
			return;
		}
		_resolved = true;
		try
		{
			Type type = AccessTools.TypeByName("EquipmentAndQuickSlots.API");
			if (type != null)
			{
				_eaqsIsSlotCell = AccessTools.Method(type, "IsSlotCell", new Type[3]
				{
					typeof(int),
					typeof(int),
					typeof(string).MakeByRefType()
				}, (Type[])null);
			}
			if (_eaqsIsSlotCell != null)
			{
				KMartBoysPlugin.Log("Equipment and Quick Slots detected: its slots will be skipped.");
			}
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.Log("EAQS compatibility lookup failed: " + ex.Message);
			_eaqsIsSlotCell = null;
		}
	}

	public static bool IsSpecialSlot(Vector2i pos)
	{
		//IL_001d: 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)
		Resolve();
		if (_eaqsIsSlotCell == null)
		{
			return false;
		}
		try
		{
			object[] parameters = new object[3] { pos.x, pos.y, null };
			return (bool)_eaqsIsSlotCell.Invoke(null, parameters);
		}
		catch
		{
			return false;
		}
	}
}
[BepInPlugin("matt.valheim.kmartboysmusthavemod", "K-MartBoysMustHaveMod", "1.13.1")]
public class KMartBoysPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "matt.valheim.kmartboysmusthavemod";

	public const string PluginName = "K-MartBoysMustHaveMod";

	public const string PluginVersion = "1.13.1";

	internal static KMartBoysPlugin Instance;

	internal static ConfigEntry<bool> ModEnabled;

	internal static ConfigEntry<KeyCode> DepositKey;

	internal static ConfigEntry<KeyCode> DepositModifier;

	internal static ConfigEntry<float> Radius;

	internal static ConfigEntry<bool> AllowWhileInventoryOpen;

	internal static ConfigEntry<bool> IgnoreHotbar;

	internal static ConfigEntry<bool> IgnoreEquipped;

	internal static ConfigEntry<bool> DepositNonStackables;

	internal static ConfigEntry<bool> IgnoreAmmo;

	internal static ConfigEntry<bool> SlotLockEnabled;

	internal static ConfigEntry<LockClick> SlotLockClick;

	internal static ConfigEntry<KeyCode> SlotLockModifier;

	internal static ConfigEntry<Color> SlotLockColor;

	internal static ConfigEntry<bool> CenterMessageEnabled;

	internal static ConfigEntry<bool> SummaryMessageEnabled;

	internal static ConfigEntry<string> SummaryMessage;

	internal static ConfigEntry<string> NothingToDepositMessage;

	internal static ConfigEntry<string> NoContainersMessage;

	internal static ConfigEntry<int>[] TierMinItems;

	internal static ConfigEntry<string>[] TierMessages;

	internal static ConfigEntry<bool> StockEnabled;

	internal static ConfigEntry<bool> StockInBuildMenu;

	internal static ConfigEntry<string> StockFormat;

	internal static ConfigEntry<StockDisplayMode> StockDisplay;

	internal static ConfigEntry<string> StockAmountFormat;

	internal static ConfigEntry<Color> StockEnoughColor;

	internal static ConfigEntry<Color> StockShortColor;

	internal static ConfigEntry<float> StockFontSize;

	internal static ConfigEntry<float> StockOffsetX;

	internal static ConfigEntry<float> StockOffsetY;

	internal static ConfigEntry<float> StockRadius;

	internal static ConfigEntry<float> StockRefreshSeconds;

	internal static ConfigEntry<bool> StockOnlyAccessible;

	internal static ConfigEntry<bool> CraftEnabled;

	internal static ConfigEntry<bool> CraftAllowBuilding;

	internal static ConfigEntry<float> CraftRadius;

	internal static ConfigEntry<bool> CraftIgnoreMoving;

	internal static ConfigEntry<bool> CraftOnlyPlayerBuilt;

	internal static ConfigEntry<bool> CraftFixColors;

	internal static ConfigEntry<bool> RefuelEnabled;

	internal static ConfigEntry<float> RefuelInterval;

	internal static ConfigEntry<float> RefuelRadius;

	internal static ConfigEntry<bool> RefuelFireplaces;

	internal static ConfigEntry<bool> RefuelOvens;

	internal static ConfigEntry<bool> RefuelSmelters;

	internal static ConfigEntry<float> RefuelBelowPercent;

	internal static ConfigEntry<int> RefuelKeepReserve;

	internal static ConfigEntry<bool> RefuelLeaveOnePerChest;

	internal static ConfigEntry<bool> RefuelUseInventory;

	internal static ConfigEntry<string> RefuelExcluded;

	internal static ConfigEntry<bool> RefuelShowMessage;

	internal static ConfigEntry<bool> FillSmelters;

	internal static ConfigEntry<bool> FillEitrRefinery;

	internal static ConfigEntry<bool> FillKilns;

	internal static ConfigEntry<bool> FillWindmills;

	internal static ConfigEntry<bool> FillSpinningWheels;

	internal static ConfigEntry<bool> DeathMessageEnabled;

	internal static ConfigEntry<string> DeathMessages;

	internal static ConfigEntry<DeathChatChannel> DeathMessageChannel;

	internal static ConfigEntry<bool> AutoRepairEnabled;

	internal static ConfigEntry<bool> AutoRepairShowMessage;

	internal static ConfigEntry<bool> ClockEnabled;

	internal static ConfigEntry<string> ClockFormat;

	internal static ConfigEntry<int> ClockMinuteStep;

	internal static ConfigEntry<ClockAnchor> ClockPosition;

	internal static ConfigEntry<float> ClockOffsetX;

	internal static ConfigEntry<float> ClockOffsetY;

	internal static ConfigEntry<float> ClockFontSize;

	internal static ConfigEntry<Color> ClockColor;

	internal static ConfigEntry<KeyCode> ShipEditModifier;

	internal static ConfigEntry<CustomImageSource> ImagesFrom;

	internal static ConfigEntry<string> TrustedPlayers;

	internal static ConfigEntry<string> FavoriteSailUrl;

	internal static ConfigEntry<bool> ApplyFavoriteWhenSteering;

	internal static ConfigEntry<bool> ShipNamesEnabled;

	internal static ConfigEntry<bool> ShowShipNameTags;

	internal static ConfigEntry<float> ShipNameTagDistance;

	internal static ConfigEntry<float> ShipNameTagHeight;

	internal static ConfigEntry<float> ShipNameTagFontSize;

	internal static ConfigEntry<Color> ShipNameTagColor;

	internal static ConfigEntry<bool> SortEnabled;

	internal static ConfigEntry<SortMode> SortModeSetting;

	internal static ConfigEntry<bool> SortSkipHotbar;

	internal static ConfigEntry<bool> SortMergeStacks;

	internal static ConfigEntry<float> SortPlayerOffsetX;

	internal static ConfigEntry<float> SortPlayerOffsetY;

	internal static ConfigEntry<float> SortChestOffsetX;

	internal static ConfigEntry<float> SortChestOffsetY;

	internal static ConfigEntry<bool> BannerFitImage;

	internal static ConfigEntry<bool> BannerFlipImage;

	private const int TierCount = 6;

	private static readonly int[] DefaultTierMin = new int[6] { 1, 2, 10, 50, 200, 500 };

	private static readonly string[] DefaultTierText = new string[6] { "One whole item. Great Job, Jackass.", "Great Job, Jackass", "{items} items stashed. Great Job, Jackass!", "Look at you go! {items} items. Great Job, Jackass!", "{items} items?! Your back thanks you. Great Job, Jackass!", "{items} ITEMS ACROSS {containers} CHESTS. Odin weeps. Great Job, Jackass!!" };

	private const string PlaceholderHelp = " Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers.";

	private Harmony _harmony;

	private FileSystemWatcher _watcher;

	private volatile bool _configFileChanged;

	private float _reloadAt;

	private int _order;

	internal static bool OtherCraftModLoaded;

	internal static bool OtherRefuelModLoaded;

	internal static bool OtherRepairModLoaded;

	private static readonly string[] RepairMods = new string[3] { "mtsukn.AutoRepair", "Tekla.AutoRepair", "aedenthorn.AutoRepair" };

	private static readonly string[] CraftFromContainerMods = new string[5] { "com.mikeg.valheim.nearbycrafting", "aedenthorn.CraftFromContainers", "Azumatt.AzuCraftyBoxes", "org.bepinex.plugins.craftfromcontainers", "com.maxsch.valheim.MultiUserChest" };

	private static readonly string[] RefuelMods = new string[2] { "simplifydave.autorefillfires", "aedenthorn.AutoFuel" };

	private static readonly HashSet<string> LoggedKeys = new HashSet<string>();

	private ConfigEntry<T> Bind<T>(string section, string key, string dispName, T defaultValue, string description, AcceptableValueBase range = null)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Expected O, but got Unknown
		ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes
		{
			DispName = dispName,
			Order = 1000 - _order++
		};
		return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, range, new object[1] { configurationManagerAttributes }));
	}

	private void Awake()
	{
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_045d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0496: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b0d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0d14: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e7f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0e89: Expected O, but got Unknown
		Instance = this;
		((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
		ModEnabled = Bind("1 - General", "Enabled", "Mod enabled", defaultValue: true, "Turn the whole mod on or off.");
		DepositKey = Bind<KeyCode>("1 - General", "DepositKey", "Deposit key", (KeyCode)287, "Key that deposits your items into nearby matching containers.");
		DepositModifier = Bind<KeyCode>("1 - General", "DepositModifier", "Deposit modifier key", (KeyCode)0, "Optional key that must be held together with the deposit key (e.g. LeftShift). None = no modifier.");
		Radius = Bind("1 - General", "Radius", "Search radius (m)", 10f, "Radius in meters around you to search for containers.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f));
		AllowWhileInventoryOpen = Bind("1 - General", "AllowWhileInventoryOpen", "Works with inventory open", defaultValue: true, "Allow the deposit key to work while the inventory screen is open.");
		IgnoreHotbar = Bind("2 - Filters", "IgnoreHotbar", "Skip hotbar", defaultValue: true, "Never deposit items in your hotbar (the top row of the inventory, slots 1-8).");
		IgnoreEquipped = Bind("2 - Filters", "IgnoreEquipped", "Skip equipped items", defaultValue: true, "Never deposit items you have equipped (weapons, tools, armor, utility items).");
		IgnoreAmmo = Bind("2 - Filters", "IgnoreAmmo", "Skip ammo", defaultValue: true, "Never deposit ammo (arrows, bolts and other ammo you can equip), even if a chest already has the same kind.");
		DepositNonStackables = Bind("2 - Filters", "DepositNonStackables", "Deposit non-stackables", defaultValue: true, "Also deposit non-stacking items (tools, weapons, armor) when a container already has the same item.");
		SlotLockEnabled = Bind("3 - Slot Locking", "Enabled", "Slot locking enabled", defaultValue: true, "Allow locking inventory slots so they are never deposited.");
		SlotLockClick = Bind("3 - Slot Locking", "LockClick", "Lock mouse button", LockClick.MiddleClick, "Mouse button that locks / unlocks the inventory slot under the cursor (inventory open). Disabled = off.");
		SlotLockModifier = Bind<KeyCode>("3 - Slot Locking", "LockModifierKey", "Lock modifier + left-click", (KeyCode)0, "Optional alternative: hold this key and left-click a slot to lock / unlock it. None = off. (LeftAlt is already used by Crop Utils, Better Archery and Equipment and Quick Slots.)");
		SlotLockColor = Bind<Color>("3 - Slot Locking", "LockMarkerColor", "Lock marker color", new Color(0.6f, 0.2f, 0.95f, 0.5f), "Color of the marker drawn on locked slots (RGBA). The corner badge uses the same color at full opacity.");
		CenterMessageEnabled = Bind("4 - Messages", "CenterMessageEnabled", "Show center message", defaultValue: true, "Show the big center-screen message after depositing (wording set by the tiers below).");
		SummaryMessageEnabled = Bind("4 - Messages", "SummaryMessageEnabled", "Show summary message", defaultValue: true, "Show the small top-left summary / status messages.");
		SummaryMessage = Bind("4 - Messages", "SummaryMessage", "Summary text", "Deposited {items} {itemsWord} into {containers} {containersWord}", "Top-left message after a successful deposit. Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers.");
		NothingToDepositMessage = Bind("4 - Messages", "NothingToDepositMessage", "Nothing-to-deposit text", "Nothing to deposit", "Top-left message when nothing matched. Leave empty for no message.");
		NoContainersMessage = Bind("4 - Messages", "NoContainersMessage", "No-containers text", "No containers in range", "Top-left message when no usable containers are nearby. Leave empty for no message.");
		TierMinItems = new ConfigEntry<int>[6];
		TierMessages = new ConfigEntry<string>[6];
		for (int i = 0; i < 6; i++)
		{
			int num = i + 1;
			TierMinItems[i] = Bind("5 - Center Message Tiers", "Tier" + num + "MinItems", "Tier " + num + " - min items", DefaultTierMin[i], "Tier " + num + " is used when at least this many items were deposited (the highest matching tier wins). 0 = tier disabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100000));
			TierMessages[i] = Bind("5 - Center Message Tiers", "Tier" + num + "Message", "Tier " + num + " - message", DefaultTierText[i], "Center-screen text for tier " + num + ". Leave empty to disable this tier. Placeholders: {items} = number of items, {containers} = number of containers, {itemsWord} = item/items, {containersWord} = container/containers.");
		}
		StockEnabled = Bind("6 - Crafting Stock", "Enabled", "Show stock at crafting", defaultValue: true, "Under each required material at a crafting station, show how many you carry and how many are in your storage boxes.");
		StockInBuildMenu = Bind("6 - Crafting Stock", "ShowInBuildMenu", "Also show in build menu", defaultValue: false, "Also show the stock line under build-piece requirements (hammer, hoe, cultivator).");
		StockDisplay = Bind("6 - Crafting Stock", "Display", "Where to show it", StockDisplayMode.InSlotNumber, "InSlotNumber = replace the number on each ingredient slot (always visible). LineBelowSlot = an extra line under the slot (can be cut off by the crafting panel).");
		StockAmountFormat = Bind("6 - Crafting Stock", "SlotNumberFormat", "Slot number text", "{total}/{need}", "Text for the ingredient slot's number when Display = InSlotNumber. Default shows have (bag + chests) / need. Placeholders: {need}, {have}, {stored}, {total}, {missing}.");
		StockFormat = Bind("6 - Crafting Stock", "Format", "Line below slot text", "{total} total\n<size=80%>{have} bag | {stored} box</size>", "Text shown under each requirement. Placeholders: {need} = amount required, {have} = in your inventory, {stored} = in storage boxes, {total} = have + stored, {missing} = how many more you need (0 if enough). \\n = new line. Unity rich text tags like <size=80%> and <color=#ff0> work.");
		StockEnoughColor = Bind<Color>("6 - Crafting Stock", "EnoughColor", "Color when you have enough", new Color(0.55f, 0.95f, 0.55f, 1f), "Text color when inventory + storage covers the requirement.");
		StockShortColor = Bind<Color>("6 - Crafting Stock", "ShortColor", "Color when short", new Color(1f, 0.55f, 0.35f, 1f), "Text color when inventory + storage is not enough.");
		StockFontSize = Bind("6 - Crafting Stock", "FontSize", "Font size", 14f, "Font size of the stock text.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 40f));
		StockOffsetX = Bind("6 - Crafting Stock", "OffsetX", "Position offset X", 0f, "Move the stock text left (-) or right (+), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-300f, 300f));
		StockOffsetY = Bind("6 - Crafting Stock", "OffsetY", "Position offset Y", -2f, "Move the stock text up (+) or down (-), in UI pixels. 0 = just below the requirement slot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-300f, 300f));
		StockRadius = Bind("6 - Crafting Stock", "StorageRadius", "Storage search radius (m)", 0f, "Only count containers within this many meters of you. 0 = every container currently loaded around you (roughly your whole base).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 500f));
		StockRefreshSeconds = Bind("6 - Crafting Stock", "RefreshSeconds", "Storage refresh interval (s)", 1f, "How often storage boxes are re-counted while a crafting screen is open.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f));
		StockOnlyAccessible = Bind("6 - Crafting Stock", "OnlyAccessibleContainers", "Only count chests you can open", defaultValue: true, "Skip private chests you don't own and chests in wards you can't access. Graves are never counted.");
		CraftEnabled = Bind("7 - Craft From Containers", "Enabled", "Craft from containers", defaultValue: true, "Crafting and upgrading can use materials from nearby containers. Your inventory is used first, then the nearest containers.");
		CraftAllowBuilding = Bind("7 - Craft From Containers", "AllowBuilding", "Build from containers", defaultValue: true, "Building (hammer, hoe, cultivator) can also use materials from nearby containers.");
		CraftRadius = Bind("7 - Craft From Containers", "ContainerRadius", "Container radius (m)", 30f, "How far from you (in meters) containers are used for crafting, building and auto-refuel fuel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
		CraftIgnoreMoving = Bind("7 - Craft From Containers", "IgnoreCartsAndShips", "Ignore carts and ships", defaultValue: true, "Don't use containers on carts or ships (safer in multiplayer).");
		CraftOnlyPlayerBuilt = Bind("7 - Craft From Containers", "OnlyPlayerBuiltContainers", "Only player-built containers", defaultValue: true, "Only use containers built by players, so dungeon and world loot chests are never touched.");
		CraftFixColors = Bind("7 - Craft From Containers", "CountContainersInRequirementColors", "Requirement colors count containers", defaultValue: true, "Requirement slots only flash red when your inventory AND nearby containers together are short.");
		RefuelEnabled = Bind("8 - Auto Refuel", "Enabled", "Auto refuel", defaultValue: true, "Every few seconds, top up fuel in nearby fires, ovens and smelters, and fill smelters, refineries, kilns, windmills and spinning wheels with their inputs, all from nearby containers.");
		RefuelInterval = Bind("8 - Auto Refuel", "IntervalSeconds", "Check every (s)", 5f, "How often (in seconds) to check nearby fuel levels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 120f));
		RefuelRadius = Bind("8 - Auto Refuel", "Radius", "Refuel radius (m)", 20f, "Fires, ovens, smelters and other processors within this many meters of you get refilled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
		RefuelFireplaces = Bind("8 - Auto Refuel", "Fires", "Refuel fires", defaultValue: true, "Campfires, hearths, braziers, bonfires, torches, sconces, hot tubs and anything else that burns fuel.");
		RefuelOvens = Bind("8 - Auto Refuel", "Ovens", "Refuel ovens", defaultValue: true, "Stone ovens and other cooking stations that use fuel.");
		RefuelSmelters = Bind("8 - Auto Refuel", "Smelters", "Refuel smelters", defaultValue: true, "Fuel for smelters, blast furnaces (coal) and eitr refineries (sap).");
		FillSmelters = Bind("8 - Auto Refuel", "FillSmelterOre", "Fill smelters & furnaces with ore", defaultValue: true, "Add ore and scrap (copper, tin, iron, silver, black metal, flametal...) to smelters and blast furnaces.");
		FillEitrRefinery = Bind("8 - Auto Refuel", "FillEitrRefinery", "Fill eitr refineries", defaultValue: true, "Add soft tissue to eitr refineries.");
		FillKilns = Bind("8 - Auto Refuel", "FillKilns", "Fill charcoal kilns", defaultValue: true, "Add wood to charcoal kilns. Careful: this turns the wood in your chests into coal. Use KeepReserve to hold some back.");
		FillWindmills = Bind("8 - Auto Refuel", "FillWindmills", "Fill windmills", defaultValue: true, "Add barley to windmills.");
		FillSpinningWheels = Bind("8 - Auto Refuel", "FillSpinningWheels", "Fill spinning wheels", defaultValue: true, "Add flax to spinning wheels.");
		RefuelBelowPercent = Bind("8 - Auto Refuel", "RefillBelowPercent", "Refill below (%)", 100f, "Only refuel when fuel drops below this percent of max. 100 = keep everything topped off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f));
		RefuelKeepReserve = Bind("8 - Auto Refuel", "KeepReserve", "Keep in reserve", 0, "Leave at least this many of each fuel or input item (wood, ore, coal...) in your containers.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10000));
		RefuelLeaveOnePerChest = Bind("8 - Auto Refuel", "LeaveOneInEachChest", "Leave 1 in each chest", defaultValue: true, "Never take the last fuel/input item out of a chest, so F6 auto-deposit still knows that chest is where it goes.");
		RefuelUseInventory = Bind("8 - Auto Refuel", "UseInventoryFuel", "Also use your inventory", defaultValue: false, "If the containers run out, also take fuel and inputs (ore, wood...) from your own inventory.");
		RefuelExcluded = Bind("8 - Auto Refuel", "ExcludedObjects", "Never refuel these", "", "Comma-separated prefab names to never refuel, e.g. piece_groundtorch_wood, piece_brazierceiling01.");
		RefuelShowMessage = Bind("8 - Auto Refuel", "ShowMessage", "Show refuel message", defaultValue: false, "Show a small top-left message when something was refueled.");
		DeathMessageEnabled = Bind("9 - Death Message", "Enabled", "Announce your deaths", defaultValue: true, "When you die, post a message in chat.");
		DeathMessages = Bind("9 - Death Message", "Messages", "Death message(s)", "I WAS AN IDIOT AND I DIED HAHAHAHAHAHA", "What you say in chat when you die. Separate several with | and one is picked at random. {name} = your character's name.");
		DeathMessageChannel = Bind("9 - Death Message", "Channel", "Chat channel", DeathChatChannel.Shout, "Shout = everyone in the world sees it. Normal = only players near you.");
		AutoRepairEnabled = Bind("10 - Auto Repair", "Enabled", "Auto repair at stations", defaultValue: true, "When you open a crafting station, repair everything in your inventory that station can repair.");
		AutoRepairShowMessage = Bind("10 - Auto Repair", "ShowMessage", "Show repair message", defaultValue: true, "Show \"Repaired N items\" when something was repaired.");
		ClockEnabled = Bind("11 - Clock", "Enabled", "Show clock", defaultValue: true, "Show an in-game 12-hour clock with the current weather.");
		ClockFormat = Bind("11 - Clock", "Format", "Clock text", "{time}  |  {weather}", "Placeholders: {time} = e.g. 7:45 PM, {weather} = current weather, {conditions} = Cold/Freezing/Wet, {day} = day number. \\n = new line. Example: Day {day}  {time}  {weather} ({conditions})");
		ClockMinuteStep = Bind("11 - Clock", "MinuteStep", "Round minutes to", 1, "Show the time in steps of this many minutes (1 = every minute, 5 = 7:45, 7:50...).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60));
		ClockPosition = Bind("11 - Clock", "Position", "Screen position", ClockAnchor.TopCenter, "Which corner/edge of the screen the clock sits in.");
		ClockOffsetX = Bind("11 - Clock", "OffsetX", "Offset X", 0f, "Move the clock left (-) or right (+), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f));
		ClockOffsetY = Bind("11 - Clock", "OffsetY", "Offset Y", -10f, "Move the clock up (+) or down (-), in UI pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2000f, 2000f));
		ClockFontSize = Bind("11 - Clock", "FontSize", "Font size", 22f, "Clock text size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 60f));
		ClockColor = Bind<Color>("11 - Clock", "Color", "Text color", new Color(1f, 0.93f, 0.75f, 1f), "Clock text color.");
		ShipEditModifier = Bind<KeyCode>("12 - Ships & Banners", "EditModifierKey", "Edit modifier key", (KeyCode)306, "Hold this while looking at a ship or banner: + Use sets the image, + Shift + Use names a ship. None = no key needed.");
		ImagesFrom = Bind("12 - Ships & Banners", "ShowImagesFrom", "Show custom images from", CustomImageSource.Everyone, "Everyone = show every custom sail/banner. TrustedPlayersOnly = only images set by you or the players listed below. Off = never download or show custom images. (Your game downloads the image from its URL, so that site sees your IP.)");
		TrustedPlayers = Bind("12 - Ships & Banners", "TrustedPlayers", "Trusted players", "", "Comma-separated character names whose images you'll see when ShowImagesFrom = TrustedPlayersOnly.");
		FavoriteSailUrl = Bind("12 - Ships & Banners", "FavoriteSailUrl", "Favorite sail image URL", "", "If set, this image is put on the sail when you take the helm of a ship.");
		ApplyFavoriteWhenSteering = Bind("12 - Ships & Banners", "ApplyFavoriteWhenSteering", "Apply favorite when steering", defaultValue: true, "Put your favorite sail image on any ship you start steering.");
		ShipNamesEnabled = Bind("12 - Ships & Banners", "ShipNames", "Ship names", defaultValue: true, "Allow naming ships and show their names.");
		ShowShipNameTags = Bind("12 - Ships & Banners", "ShowNameTags", "Floating ship names", defaultValue: true, "Show ship names floating above the ships.");
		ShipNameTagDistance = Bind("12 - Ships & Banners", "NameTagDistance", "Name visible within (m)", 10f, "Ship names only show when you're within this many meters of the ship.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 300f));
		ShipNameTagHeight = Bind("12 - Ships & Banners", "NameTagHeight", "Name height above ship (m)", 9f, "How high above the ship the name floats.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f));
		ShipNameTagFontSize = Bind("12 - Ships & Banners", "NameTagFontSize", "Name font size", 26f, "Floating name size.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 60f));
		BannerFitImage = Bind("12 - Ships & Banners", "BannerFitImage", "Fit image to banner", defaultValue: true, "Show the whole custom image once across hanging banners (fixes the cut-in-half, mirrored look of the game's banner layout).");
		BannerFlipImage = Bind("12 - Ships & Banners", "BannerFlipImage", "Flip banner image", defaultValue: false, "Mirror custom banner images left-to-right. Turn on if your banner image shows up backwards.");
		ShipNameTagColor = Bind<Color>("12 - Ships & Banners", "NameTagColor", "Name color", new Color(1f, 0.85f, 0.4f, 1f), "Floating name color.");
		SortEnabled = Bind("13 - Sorting", "Enabled", "Sort buttons", defaultValue: true, "Show a Sort button on your inventory and on open chests. Left-click sorts, right-click changes the sort mode.");
		SortModeSetting = Bind("13 - Sorting", "Mode", "Sort by", SortMode.Name, "Name = A to Z. Type = weapons, ammo, shields, armor, utility, tools, food, fish, materials, trophies. Value = most valuable stacks first. Quality = highest upgrade level first. Power = strongest damage / armor / block first. Weight = heaviest stacks first.");
		SortSkipHotbar = Bind("13 - Sorting", "SkipHotbar", "Keep hotbar in place", defaultValue: true, "Don't move items in your hotbar (top row) when sorting your inventory. Locked slots never move either.");
		SortMergeStacks = Bind("13 - Sorting", "MergeStacks", "Merge partial stacks", defaultValue: true, "Combine partial stacks of the same item while sorting.");
		SortPlayerOffsetX = Bind("13 - Sorting", "InventoryButtonOffsetX", "Inventory button X", 0f, "Move your inventory's Sort button left (-) or right (+).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f));
		SortPlayerOffsetY = Bind("13 - Sorting", "InventoryButtonOffsetY", "Inventory button Y", 4f, "Move your inventory's Sort button up (+) or down (-).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f));
		SortChestOffsetX = Bind("13 - Sorting", "ChestButtonOffsetX", "Chest button X", 0f, "Move the chest Sort button left (-) or right (+).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f));
		SortChestOffsetY = Bind("13 - Sorting", "ChestButtonOffsetY", "Chest button Y", 4f, "Move the chest Sort button up (+) or down (-).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1500f, 1500f));
		_harmony = new Harmony("matt.valheim.kmartboysmusthavemod");
		_harmony.PatchAll(Assembly.GetExecutingAssembly());
		WatchConfigFile();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"K-MartBoysMustHaveMod 1.13.1 loaded.");
	}

	private void WatchConfigFile()
	{
		try
		{
			string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
			_watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath));
			_watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
			_watcher.Changed += OnConfigFileEvent;
			_watcher.Created += OnConfigFileEvent;
			_watcher.Renamed += OnConfigFileEvent;
			_watcher.IncludeSubdirectories = false;
			_watcher.SynchronizingObject = null;
			_watcher.EnableRaisingEvents = true;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not watch config file for changes: " + ex.Message));
		}
	}

	private void OnConfigFileEvent(object sender, FileSystemEventArgs e)
	{
		_configFileChanged = true;
	}

	private void ReloadConfigIfChanged()
	{
		if (_configFileChanged)
		{
			_configFileChanged = false;
			_reloadAt = Time.unscaledTime + 0.5f;
		}
		if (_reloadAt > 0f && Time.unscaledTime >= _reloadAt)
		{
			_reloadAt = 0f;
			try
			{
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload failed: " + ex.Message));
			}
		}
	}

	private void Start()
	{
		string[] craftFromContainerMods = CraftFromContainerMods;
		foreach (string text in craftFromContainerMods)
		{
			if (Chainloader.PluginInfos.ContainsKey(text))
			{
				OtherCraftModLoaded = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Another craft-from-containers mod is installed (" + text + "). This mod's Craft From Containers is turned OFF to avoid counting chests twice. Remove that mod to use ours."));
			}
		}
		craftFromContainerMods = RepairMods;
		foreach (string text2 in craftFromContainerMods)
		{
			if (Chainloader.PluginInfos.ContainsKey(text2))
			{
				OtherRepairModLoaded = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Another auto-repair mod is installed (" + text2 + "). This mod's Auto Repair is turned OFF. Remove that mod to use ours."));
			}
		}
		craftFromContainerMods = RefuelMods;
		foreach (string text3 in craftFromContainerMods)
		{
			if (Chainloader.PluginInfos.ContainsKey(text3))
			{
				OtherRefuelModLoaded = true;
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Another auto-refuel mod is installed (" + text3 + "). This mod's Auto Refuel is turned OFF to avoid double refueling. Remove that mod to use ours."));
			}
		}
	}

	private void OnDestroy()
	{
		if (_watcher != null)
		{
			_watcher.Dispose();
		}
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private void Update()
	{
		//IL_003e: 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_005d: Unknown result type (might be due to invalid IL or missing references)
		ReloadConfigIfChanged();
		ClockHud.Tick();
		ShipNameTags.Tick();
		if (!ModEnabled.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null))
		{
			SlotLockInput.Poll(localPlayer);
			Refueler.Tick(localPlayer);
			if (ZInput.GetKeyDown(DepositKey.Value, false) && ((int)DepositModifier.Value == 0 || ZInput.GetKey(DepositModifier.Value, false)) && CanTakeHotkey())
			{
				Depositor.DepositNearby(localPlayer);
			}
		}
	}

	private static bool CanTakeHotkey()
	{
		if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
		{
			return false;
		}
		if (Console.IsVisible())
		{
			return false;
		}
		if (TextInput.IsVisible())
		{
			return false;
		}
		if (Menu.IsVisible())
		{
			return false;
		}
		if (Minimap.IsOpen())
		{
			return false;
		}
		if (StoreGui.IsVisible())
		{
			return false;
		}
		if (GameCamera.InFreeFly())
		{
			return false;
		}
		if (!AllowWhileInventoryOpen.Value && InventoryGui.IsVisible())
		{
			return false;
		}
		return true;
	}

	internal static void Log(string msg)
	{
		if ((Object)(object)Instance != (Object)null)
		{
			((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
		}
	}

	internal static void LogOnce(string key, string msg)
	{
		if (!((Object)(object)Instance == (Object)null) && LoggedKeys.Add(key))
		{
			((BaseUnityPlugin)Instance).Logger.LogWarning((object)msg);
		}
	}
}
internal static class Refueler
{
	private enum ProcessorKind
	{
		Smelter,
		EitrRefinery,
		Kiln,
		Windmill,
		SpinningWheel
	}

	private class FuelPool
	{
		public List<Container> Containers;

		public Inventory PlayerInventory;
	}

	private static readonly FieldRef<Fireplace, ZNetView> FireplaceNView = AccessTools.FieldRefAccess<Fireplace, ZNetView>("m_nview");

	private static readonly FieldRef<Smelter, ZNetView> SmelterNView = AccessTools.FieldRefAccess<Smelter, ZNetView>("m_nview");

	private static readonly FieldRef<CookingStation, ZNetView> CookingNView = AccessTools.FieldRefAccess<CookingStation, ZNetView>("m_nview");

	private static readonly MethodInfo SmelterGetQueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null);

	private static float _nextRun;

	private static string _excludedRaw;

	private static readonly HashSet<string> Excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	public static void Tick(Player player)
	{
		if (!KMartBoysPlugin.RefuelEnabled.Value || KMartBoysPlugin.OtherRefuelModLoaded || (Object)(object)player == (Object)null || ((Character)player).IsDead() || Time.time < _nextRun)
		{
			return;
		}
		_nextRun = Time.time + Mathf.Max(1f, KMartBoysPlugin.RefuelInterval.Value);
		try
		{
			Run(player);
		}
		catch (Exception ex)
		{
			KMartBoysPlugin.LogOnce("refuel", "Auto-refuel error: " + ex);
		}
	}

	private static void Run(Player player)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_0131: 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_02a9: Unknown result type (might be due to invalid IL or missing references)
		RefreshExcluded();
		Vector3 position = ((Component)player).transform.position;
		float value = KMartBoysPlugin.RefuelRadius.Value;
		float threshold = Mathf.Clamp01(KMartBoysPlugin.RefuelBelowPercent.Value / 100f);
		FuelPool pool = null;
		int num = 0;
		if (KMartBoysPlugin.RefuelFireplaces.Value)
		{
			Fireplace[] array = Object.FindObjectsByType<Fireplace>((FindObjectsSortMode)0);
			foreach (Fireplace val in array)
			{
				if ((Object)(object)val == (Object)null || val.m_infiniteFuel || (Object)(object)val.m_fuelItem == (Object)null || val.m_maxFuel <= 0f || !InRange((Behaviour)(object)val, position, value) || IsExcluded(((Component)val).gameObject))
				{
					continue;
				}
				int num2 = MissingFuel(FireplaceNView.Invoke(val), val.m_maxFuel, threshold);
				if (num2 > 0)
				{
					int num3 = TakeItem(ref pool, player, FuelName(val.m_fuelItem), num2);
					if (num3 > 0)
					{
						val.AddFuel((float)num3);
						num++;
					}
				}
			}
		}
		Smelter[] array2 = Object.FindObjectsByType<Smelter>((FindObjectsSortMode)0);
		foreach (Smelter val2 in array2)
		{
			if ((Object)(object)val2 == (Object)null || !InRange((Behaviour)(object)val2, position, value) || IsExcluded(((Component)val2).gameObject))
			{
				continue;
			}
			ZNetView val3 = SmelterNView.Invoke(val2);
			if ((Object)(object)val3 == (Object)null || !val3.IsValid())
			{
				continue;
			}
			bool flag = false;
			if (KMartBoysPlugin.RefuelSmelters.Value && (Object)(object)val2.m_fuelItem != (Object)null && val2.m_maxFuel > 0)
			{
				int num4 = MissingFuel(val3, val2.m_maxFuel, threshold);
				if (num4 > 0)
				{
					int num5 = TakeItem(ref pool, player, FuelName(val2.m_fuelItem), num4);
					for (int j = 0; j < num5; j++)
					{
						val3.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
					}
					flag = flag || num5 > 0;
				}
			}
			if (FillInputsFor(Classify(val2)) && val2.m_maxOre > 0 && val2.m_conversion != null)
			{
				flag |= FillInputs(ref pool, player, val2, val3) > 0;
			}
			if (flag)
			{
				num++;
			}
		}
		if (KMartBoysPlugin.RefuelOvens.Value)
		{
			CookingStation[] array3 = Object.FindObjectsByType<CookingStation>((FindObjectsSortMode)0);
			foreach (CookingStation val4 in array3)
			{
				if ((Object)(object)val4 == (Object)null || !val4.m_useFuel || (Object)(object)val4.m_fuelItem == (Object)null || val4.m_maxFuel <= 0 || !InRange((Behaviour)(object)val4, position, value) || IsExcluded(((Component)val4).gameObject))
				{
					continue;
				}
				ZNetView val5 = CookingNView.Invoke(val4);
				int num6 = MissingFuel(val5, val4.m_maxFuel, threshold);
				if (num6 <= 0)
				{
					continue;
				}
				int num7 = TakeItem(ref pool, player, FuelName(val4.m_fuelItem), num6);
				if (num7 > 0)
				{
					for (int k = 0; k < num7; k++)
					{
						val5.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
					}
					num++;
				}
			}
		}
		if (num > 0 && KMartBoysPlugin.RefuelShowMessage.Value)
		{
			((Character)player).Message((MessageType)1, "Refilled " + num + " station" + ((num == 1) ? "" : "s"), 0, (Sprite)null, false);
		}
	}

	private static ProcessorKind Classify(Smelter s)
	{
		string text = Utils.GetPrefabName(((Component)s).gameObject).ToLowerInvariant();
		if (text.Contains("eitrrefinery"))
		{
			return ProcessorKind.EitrRefinery;
		}
		if (text.Contains("kiln"))
		{
			return ProcessorKind.Kiln;
		}
		if (text.Contains("windmill"))
		{
			return ProcessorKind.Windmill;
		}
		if (text.Contains("spinningwheel"))
		{
			return ProcessorKind.SpinningWheel;
		}
		return ProcessorKind.Smelter;
	}

	private static bool FillInputsFor(ProcessorKind kind)
	{
		return kind switch
		{
			ProcessorKind.EitrRefinery => KMartBoysPlugin.FillEitrRefinery.Value, 
			ProcessorKind.Kiln => KMartBoysPlugin.FillKilns.Value, 
			ProcessorKind.Windmill => KMartBoysPlugin.FillWindmills.Value, 
			ProcessorKind.SpinningWheel => KMartBoysPlugin.FillSpinningWheels.Value, 
			_ => KMartBoysPlugin.FillSmelters.Value, 
		};
	}

	private static int FillInputs(ref FuelPool pool, Player player, Smelter s, ZNetView nview)
	{
		int num = ((SmelterGetQueueSize != null) ? ((int)SmelterGetQueueSize.Invoke(s, null)) : 0);
		int num2 = s.m_maxOre - num;
		if (num2 <= 0)
		{
			return 0;
		}
		int num3 = 0;
		foreach (ItemConversion item in s.m_conversion)
		{
			if (num2 <= 0)
			{
				break;
			}
			if (item == null || (Object)(object)item.m_from == (Object)null)
			{
				continue;
			}
			string text = FuelName(item.m_from);
			string name = ((Object)((Component)item.m_from).gameObject).name;
			if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(name))
			{
				int num4 = TakeItem(ref pool, player, text, num2);
				for (int i = 0; i < num4; i++)
				{
					nview.InvokeRPC("RPC_AddOre", new object[2] { name, false });
				}
				num2 -= num4;
				num3 += num4;
			}
		}
		return num3;
	}

	private static bool InRange(Behaviour c, Vector3 origin, float radius)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		if (c.isActiveAndEnabled)
		{
			return Vector3.Distance(origin, ((Component)c).transform.position) <= radius;
		}
		return false;
	}

	private static int MissingFuel(ZNetView nview, float maxFuel, float threshold)
	{
		if ((Object)(object)nview == (Object)null || !nview.IsValid())
		{
			return 0;
		}
		ZDO zDO = nview.GetZDO();
		if (zDO == null)
		{
			return 0;
		}
		float num = zDO.GetFloat(ZDOVars.s_fuel, 0f);
		if (num >= maxFuel * threshold && threshold < 1f)
		{
			return 0;
		}
		return Mathf.FloorToInt(maxFuel - num);
	}

	private static string FuelName(ItemDrop drop)
	{
		if (!((Object)(object)drop != (Object)null) || drop.m_itemData == null || drop.m_itemData.m_shared == null)
		{
			return null;
		}
		return drop.m_itemData.m_shared.m_name;
	}

	private static int TakeItem(ref FuelPool pool, Player player, string fuelName, int amount)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		if (string.IsNullOrEmpty(fuelName) || amount <= 0)
		{
			return 0;
		}
		if (pool == null)
		{
			pool = new FuelPool
			{
				Containers = ContainerSource.FindAround(((Component)player).transform.position, KMartBoysPlugin.CraftRadius.Value),
				PlayerInventory = (KMartBoysPlugin.RefuelUseInventory.