Decompiled source of ValheimSlots v1.0.8

plugins/ValheimSlots.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Lorcisen")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © Lorcisen 2026")]
[assembly: AssemblyDescription("Client-side Valheim inventory mod: extra rows plus equipment, weapon-set, ammo, food and mead slots.")]
[assembly: AssemblyFileVersion("1.0.8.0")]
[assembly: AssemblyInformationalVersion("1.0.8+f4b50f7952a3d7db999a49916d29114f2799f334")]
[assembly: AssemblyProduct("ValheimSlots")]
[assembly: AssemblyTitle("ValheimSlots")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.8.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimSlots
{
	internal static class QuickStackStoreCompat
	{
		public const string Guid = "goldenrevolver.quick_stack_store";

		private static MethodInfo _getPlayerConfig;

		private static MethodInfo _isSlotFavorited;

		private static object _cachedConfig;

		private static int _cachedFrame = -1;

		private static readonly object[] Args = new object[1];

		public static bool Active { get; private set; }

		public static bool IsFavoritedSlot(Vector2i pos)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (_getPlayerConfig == null || _isSlotFavorited == null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			try
			{
				if (_cachedFrame != Time.frameCount)
				{
					_cachedFrame = Time.frameCount;
					_cachedConfig = _getPlayerConfig.Invoke(null, new object[1] { Player.m_localPlayer.GetPlayerID() });
				}
				if (_cachedConfig == null)
				{
					return false;
				}
				Args[0] = pos;
				return (bool)_isSlotFavorited.Invoke(_cachedConfig, Args);
			}
			catch
			{
				_isSlotFavorited = null;
				return false;
			}
		}

		public static void TryPatch(Harmony harmony)
		{
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("goldenrevolver.quick_stack_store", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return;
			}
			try
			{
				Assembly assembly = ((object)value.Instance).GetType().Assembly;
				Type type = assembly.GetType("QuickStackStore.UserConfig");
				if (type != null)
				{
					_getPlayerConfig = AccessTools.Method(type, "GetPlayerConfig", new Type[1] { typeof(long) }, (Type[])null);
					_isSlotFavorited = AccessTools.Method(type, "IsSlotFavorited", new Type[1] { typeof(Vector2i) }, (Type[])null);
				}
				Active = _getPlayerConfig != null && _isSlotFavorited != null;
				Type type2 = assembly.GetType("QuickStackStore.CompatibilitySupport");
				Type[] array = new Type[3]
				{
					typeof(int),
					typeof(int),
					typeof(Vector2i)
				};
				MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type2, "IsEquipOrQuickSlot", array, (Type[])null));
				MethodInfo methodInfo2 = ((type2 == null) ? null : AccessTools.Method(type2, "IsEquipSlot", array, (Type[])null));
				if (methodInfo == null || methodInfo2 == null)
				{
					Plugin.Log.LogWarning((object)"QuickStackStore found but its API has changed - special slots are not protected from quick stacking.");
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(QuickStackStoreCompat), "EquipOrQuickPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(QuickStackStoreCompat), "EquipOnlyPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)"QuickStackStore compatibility active.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogWarning((object)$"QuickStackStore compatibility failed: {arg}");
			}
		}

		private static bool IsOurPlayerInventory(int height, int width)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && ((Humanoid)localPlayer).m_inventory.GetHeight() == height)
			{
				return ((Humanoid)localPlayer).m_inventory.GetWidth() == width;
			}
			return false;
		}

		private static void EquipOrQuickPostfix(int inventoryHeight, int inventoryWidth, Vector2i itemPos, ref bool __result)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!__result && IsOurPlayerInventory(inventoryHeight, inventoryWidth))
			{
				__result = SlotLayout.IsReserved(itemPos) || LockedSlots.IsOwnLocked(itemPos);
			}
		}

		private static void EquipOnlyPostfix(int inventoryHeight, int inventoryWidth, Vector2i itemPos, ref bool __result)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!__result && IsOurPlayerInventory(inventoryHeight, inventoryWidth) && !SlotLayout.IsMain(itemPos))
			{
				SlotDef slot = SlotLayout.GetSlot(itemPos);
				__result = slot == null || !slot.IsRefillable;
			}
		}
	}
	[HarmonyPatch]
	internal static class AutoEquipMove
	{
		internal static int SuppressDepth;

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void Humanoid_EquipItem(Humanoid __instance, ItemData item, bool __result)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || SuppressDepth > 0 || item == null)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Inventory inventory = ((Humanoid)val).m_inventory;
			if (!inventory.ContainsItem(item))
			{
				return;
			}
			SlotDef slot = SlotLayout.GetSlot(item.m_gridPos);
			if (slot != null && SlotLayout.Fits(slot.Kind, item))
			{
				return;
			}
			SlotDef slotDef = SlotLayout.ArmorSlotFor(item);
			if (slotDef == null && Plugin.AutoMoveWeapons.Value && item.m_gridPos.y != 0)
			{
				int activeSet = WeaponSets.ActiveSet;
				if (item == ((Humanoid)val).m_rightItem && SlotLayout.Fits(SlotKind.WeaponMain, item))
				{
					slotDef = SlotLayout.GetSlot(SlotKind.WeaponMain, activeSet);
				}
				else if (item == ((Humanoid)val).m_leftItem && SlotLayout.Fits(SlotKind.WeaponOff, item))
				{
					slotDef = SlotLayout.GetSlot(SlotKind.WeaponOff, activeSet);
				}
				else if (item == ((Humanoid)val).m_leftItem && SlotLayout.Fits(SlotKind.WeaponMain, item))
				{
					slotDef = SlotLayout.GetSlot(SlotKind.WeaponMain, activeSet);
				}
			}
			if (slotDef != null)
			{
				MoveInto(inventory, item, slotDef.GridPos);
			}
		}

		internal static bool MoveInto(Inventory inv, ItemData item, Vector2i target)
		{
			//IL_0001: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!SlotLayout.IsValidPlacement(item, target))
			{
				return false;
			}
			ItemData itemAt = inv.GetItemAt(target.x, target.y);
			Vector2i gridPos = item.m_gridPos;
			if (itemAt != null)
			{
				if (itemAt == item)
				{
					return true;
				}
				if (itemAt.m_equipped || !SlotLayout.IsValidPlacement(itemAt, gridPos))
				{
					return false;
				}
				itemAt.m_gridPos = gridPos;
			}
			item.m_gridPos = target;
			Inv.Changed(inv);
			return true;
		}
	}
	internal static class AutoRefill
	{
		private struct Pending
		{
			public SlotDef Slot;

			public string Name;

			public int Quality;
		}

		private static readonly List<Pending> PendingRefills = new List<Pending>();

		internal static void NotifyEmptying(ItemData item)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.AutoRefill.Value && AutoEquipMove.SuppressDepth <= 0)
			{
				SlotDef slot = SlotLayout.GetSlot(item.m_gridPos);
				if (slot != null && slot.IsRefillable)
				{
					PendingRefills.Add(new Pending
					{
						Slot = slot,
						Name = item.m_shared.m_name,
						Quality = item.m_quality
					});
				}
			}
		}

		internal static void Tick(Player player)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).m_inventory;
			if (PendingRefills.Count > 0)
			{
				foreach (Pending pendingRefill in PendingRefills)
				{
					Vector2i gridPos = pendingRefill.Slot.GridPos;
					if (inventory.GetItemAt(gridPos.x, gridPos.y) == null)
					{
						ItemData val = FindInMain(inventory, pendingRefill.Name, pendingRefill.Quality);
						if (val != null)
						{
							val.m_gridPos = gridPos;
							Inv.Changed(inventory);
						}
					}
				}
				PendingRefills.Clear();
			}
			if (Plugin.TopUpFromInventory.Value && !InventoryGui.IsVisible())
			{
				TopUp(inventory);
			}
		}

		private static void TopUp(Inventory inv)
		{
			bool flag = false;
			foreach (SlotDef slot in SlotLayout.Slots)
			{
				if (!slot.IsRefillable)
				{
					continue;
				}
				ItemData itemAt = inv.GetItemAt(slot.GridPos.x, slot.GridPos.y);
				if (itemAt == null || itemAt.m_stack >= itemAt.m_shared.m_maxStackSize)
				{
					continue;
				}
				ItemData val = FindInMain(inv, itemAt.m_shared.m_name, itemAt.m_quality, itemAt.m_worldLevel);
				if (val != null)
				{
					int num = Math.Min(itemAt.m_shared.m_maxStackSize - itemAt.m_stack, val.m_stack);
					itemAt.m_stack += num;
					val.m_stack -= num;
					if (val.m_stack <= 0)
					{
						inv.m_inventory.Remove(val);
					}
					flag = true;
				}
			}
			if (flag)
			{
				Inv.Changed(inv);
			}
		}

		private static ItemData FindInMain(Inventory inv, string name, int quality, int worldLevel = -1)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			ItemData val = null;
			foreach (ItemData item in inv.m_inventory)
			{
				if (!(item.m_shared.m_name != name) && item.m_quality == quality && (worldLevel < 0 || item.m_worldLevel == worldLevel) && SlotLayout.IsMain(item.m_gridPos) && !LockedSlots.IsLocked(item.m_gridPos) && !item.m_equipped && item.m_gridPos.y != 0 && (val == null || item.m_stack < val.m_stack))
				{
					val = item;
				}
			}
			if (val != null)
			{
				return val;
			}
			foreach (ItemData item2 in inv.m_inventory)
			{
				if (item2.m_shared.m_name == name && item2.m_quality == quality && item2.m_gridPos.y == 0 && !LockedSlots.IsLocked(item2.m_gridPos) && (worldLevel < 0 || item2.m_worldLevel == worldLevel))
				{
					return item2;
				}
			}
			return null;
		}

		internal static void AutoEat(Player player)
		{
			if (!Plugin.AutoEat.Value || ((Character)player).IsDead() || ((Character)player).InAttack() || ((Character)player).IsTeleporting() || InventoryGui.IsVisible() || ((Character)player).InCutscene())
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).m_inventory;
			List<Food> foods = player.GetFoods();
			float num = Plugin.AutoEatSecondsLeft.Value;
			foreach (SlotDef slot in SlotLayout.Slots)
			{
				if (slot.Kind != SlotKind.Food)
				{
					continue;
				}
				ItemData itemAt = inventory.GetItemAt(slot.GridPos.x, slot.GridPos.y);
				if (itemAt == null || (itemAt.m_shared.m_food <= 0f && itemAt.m_shared.m_foodStamina <= 0f && itemAt.m_shared.m_foodEitr <= 0f))
				{
					continue;
				}
				Food val = null;
				foreach (Food item in foods)
				{
					if (item.m_item.m_shared.m_name == itemAt.m_shared.m_name)
					{
						val = item;
					}
				}
				bool num2;
				if (val != null)
				{
					if (!(val.m_time <= num))
					{
						continue;
					}
					num2 = val.CanEatAgain();
				}
				else
				{
					num2 = foods.Count < 3;
				}
				if (num2 && player.CanEat(itemAt, false))
				{
					((Humanoid)player).UseItem(inventory, itemAt, true);
					break;
				}
			}
		}
	}
	internal static class AutoRepair
	{
		private static float _next;

		private static readonly List<ItemData> Worn = new List<ItemData>();

		internal static void Tick(Player player)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.AutoRepair.Value || Time.time < _next)
			{
				return;
			}
			_next = Time.time + 1f;
			if (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).InCutscene())
			{
				return;
			}
			Worn.Clear();
			((Humanoid)player).m_inventory.GetWornItems(Worn);
			if (Worn.Count == 0)
			{
				return;
			}
			CraftingStation val = NearestStation(((Component)player).transform.position, Plugin.AutoRepairDistance.Value);
			if ((Object)(object)val == (Object)null || !val.CheckUsable(player, false))
			{
				return;
			}
			int num = 0;
			foreach (ItemData item in Worn)
			{
				if (CanRepair(item, val))
				{
					((Character)player).RaiseSkill((SkillType)107, 1f - item.m_durability / item.GetMaxDurability());
					item.m_durability = item.GetMaxDurability();
					num++;
				}
			}
			if (num != 0)
			{
				val.m_repairItemDoneEffects.Create(((Component)val).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				string text = Localization.instance.Localize(val.m_name);
				((Character)player).Message((MessageType)2, (num == 1) ? L.T("Repaired 1 item at " + text, "Reparerade 1 föremål vid " + text) : L.T($"Repaired {num} items at {text}", $"Reparerade {num} föremål vid {text}"), 0, (Sprite)null, false);
			}
		}

		private static CraftingStation NearestStation(Vector3 pos, float maxDistance)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			CraftingStation result = null;
			float num = maxDistance;
			foreach (CraftingStation allStation in CraftingStation.m_allStations)
			{
				if (!((Object)(object)allStation == (Object)null) && allStation.m_canRepair)
				{
					float num2 = Vector3.Distance(pos, ((Component)allStation).transform.position);
					if (num2 <= num)
					{
						result = allStation;
						num = num2;
					}
				}
			}
			return result;
		}

		private static bool CanRepair(ItemData item, CraftingStation station)
		{
			if (!item.m_shared.m_canBeReparied)
			{
				return false;
			}
			Recipe recipe = ObjectDB.instance.GetRecipe(item);
			if ((Object)(object)recipe == (Object)null || ((Object)(object)recipe.m_craftingStation == (Object)null && (Object)(object)recipe.m_repairStation == (Object)null))
			{
				return false;
			}
			if ((!((Object)(object)recipe.m_repairStation != (Object)null) || !(recipe.m_repairStation.m_name == station.m_name)) && (!((Object)(object)recipe.m_craftingStation != (Object)null) || !(recipe.m_craftingStation.m_name == station.m_name)) && item.m_worldLevel >= Game.m_worldLevel)
			{
				return false;
			}
			return Mathf.Min(station.GetLevel(true), 4) >= recipe.m_minStationLevel;
		}
	}
	internal static class CheatCleaner
	{
		private const float Radius = 30f;

		private const int MaxCookingSlots = 10;

		private static float _nextAuto;

		private static readonly List<Piece> Pieces = new List<Piece>();

		internal static void Tick(Player player)
		{
			if (Plugin.AutoClearCheated.Value && !(Time.time < _nextAuto))
			{
				_nextAuto = Time.time + 1f;
				ClearInventory(((Humanoid)player).m_inventory);
				ClearProfile();
			}
		}

		private static bool ClearProfile()
		{
			Game instance = Game.instance;
			PlayerProfile val = ((instance != null) ? instance.GetPlayerProfile() : null);
			if (val == null || !val.m_usedCheats)
			{
				return false;
			}
			val.m_usedCheats = false;
			Plugin.Log.LogInfo((object)"CheatCleaner: removed the character's used-cheats flag.");
			return true;
		}

		internal static void ClearAround(Player player)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			int num = ClearInventory(((Humanoid)player).m_inventory);
			bool flag = ClearProfile();
			int num2 = 0;
			int num3 = 0;
			Pieces.Clear();
			Piece.GetAllPiecesInRadius(((Component)player).transform.position, 30f, Pieces);
			foreach (Piece piece in Pieces)
			{
				ZNetView nview = piece.m_nview;
				if ((Object)(object)nview == (Object)null || !nview.IsValid())
				{
					continue;
				}
				ZDO zDO = nview.GetZDO();
				bool flag2 = zDO.GetBool(ZDOVars.s_cheated, false) || zDO.GetBool(ZDOVars.s_cheatedQueued, false);
				for (int i = 0; i < 10; i++)
				{
					if (flag2)
					{
						break;
					}
					flag2 = zDO.GetBool(ZDOVars.s_cheatedQueued + i, false);
				}
				Container component = ((Component)piece).GetComponent<Container>();
				bool flag3 = (Object)(object)component != (Object)null && !component.IsInUse() && HasCheated(component.GetInventory());
				if (!flag2 && !flag3)
				{
					continue;
				}
				if (!nview.IsOwner())
				{
					nview.ClaimOwnership();
				}
				if (flag2)
				{
					if (zDO.GetBool(ZDOVars.s_cheated, false))
					{
						zDO.Set(ZDOVars.s_cheated, false);
					}
					if (zDO.GetBool(ZDOVars.s_cheatedQueued, false))
					{
						zDO.Set(ZDOVars.s_cheatedQueued, false);
					}
					for (int j = 0; j < 10; j++)
					{
						if (zDO.GetBool(ZDOVars.s_cheatedQueued + j, false))
						{
							zDO.Set(ZDOVars.s_cheatedQueued + j, false);
						}
					}
					num2++;
				}
				if (flag3)
				{
					num3 += ClearInventory(component.GetInventory());
				}
			}
			((Character)player).Message((MessageType)2, L.T($"Cheat flag removed: {num} items in inventory, {num2} buildings, {num3} items in chests", $"Fuskmarkering borttagen: {num} föremål i inventoryt, {num2} byggnader, {num3} föremål i kistor") + (flag ? L.T(", character", ", karaktären") : ""), 0, (Sprite)null, false);
			Plugin.Log.LogInfo((object)$"CheatCleaner: inventory {num}, pieces {num2}, chest items {num3} (radie {30f} m).");
		}

		private static bool HasCheated(Inventory inv)
		{
			foreach (ItemData item in inv.m_inventory)
			{
				if (item.m_cheated)
				{
					return true;
				}
			}
			return false;
		}

		private static int ClearInventory(Inventory inv)
		{
			int num = 0;
			foreach (ItemData item in inv.m_inventory)
			{
				if (item.m_cheated)
				{
					item.m_cheated = false;
					num++;
				}
			}
			if (num > 0)
			{
				inv.m_cheatedPopup = false;
				Inv.Changed(inv);
			}
			return num;
		}
	}
	[HarmonyPatch]
	internal static class GraveTracker
	{
		private sealed class Grave
		{
			public long PlayerId;

			public string World;

			public Vector3 Pos;

			public int Day;

			public float MissingSince = -1f;
		}

		private const float SearchRadius = 20f;

		private const float ConfirmGoneRadius = 25f;

		private const float ConfirmGoneSeconds = 5f;

		private static readonly List<Grave> Graves = new List<Grave>();

		private static bool _loaded;

		private static float _nextCheck;

		private static string FilePath => Path.Combine(Paths.ConfigPath, "lorcisen.valheimslots.graves.txt");

		internal static Vector3? Nearest(Player player, out float distance)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			distance = 0f;
			EnsureLoaded();
			Vector3? result = null;
			float num = float.MaxValue;
			foreach (Grave item in Current(player))
			{
				float num2 = Vector3.Distance(((Component)player).transform.position, item.Pos);
				if (num2 < num)
				{
					num = num2;
					result = item.Pos;
				}
			}
			distance = num;
			return result;
		}

		[HarmonyPatch(typeof(Player), "CreateTombStone")]
		[HarmonyPrefix]
		private static void Player_CreateTombStone_Prefix(Player __instance, out bool __state)
		{
			__state = (Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Humanoid)__instance).m_inventory.NrOfItems() > 0 && (Object)(object)ZoneSystem.instance != (Object)null && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)23);
		}

		[HarmonyPatch(typeof(Player), "CreateTombStone")]
		[HarmonyPostfix]
		private static void Player_CreateTombStone_Postfix(Player __instance, bool __state)
		{
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (__state && !((Object)(object)ZNet.instance == (Object)null) && !((Object)(object)EnvMan.instance == (Object)null))
			{
				EnsureLoaded();
				Graves.Add(new Grave
				{
					PlayerId = Game.instance.GetPlayerProfile().GetPlayerID(),
					World = ZNet.instance.GetWorldName(),
					Pos = ((Character)__instance).GetCenterPoint(),
					Day = EnvMan.instance.GetDay(ZNet.instance.GetTimeSeconds())
				});
				Save();
			}
		}

		internal static void Tick(Player player)
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _nextCheck)
			{
				return;
			}
			_nextCheck = Time.time + 1f;
			EnsureLoaded();
			List<Grave> list = Current(player);
			if (list.Count == 0)
			{
				return;
			}
			long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
			TombStone[] array = null;
			bool flag = false;
			foreach (Grave item in list)
			{
				float num = Vector3.Distance(((Component)player).transform.position, item.Pos);
				if (num > 45f)
				{
					item.MissingSince = -1f;
					continue;
				}
				if (array == null)
				{
					array = Object.FindObjectsByType<TombStone>((FindObjectsSortMode)0);
				}
				TombStone val = null;
				TombStone[] array2 = array;
				foreach (TombStone val2 in array2)
				{
					if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_nview == (Object)null) && val2.m_nview.IsValid() && val2.GetOwner() == playerID && Vector3.Distance(((Component)val2).transform.position, item.Pos) <= 20f)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val != (Object)null)
				{
					item.MissingSince = -1f;
					if (Vector3.Distance(((Component)val).transform.position, item.Pos) > 1f)
					{
						item.Pos = ((Component)val).transform.position;
						flag = true;
					}
				}
				else if (!(num > 25f))
				{
					if (item.MissingSince < 0f)
					{
						item.MissingSince = Time.time;
					}
					else if (Time.time - item.MissingSince >= 5f)
					{
						RemoveDeathPin(item.Pos);
						Graves.Remove(item);
						flag = true;
						((Character)player).Message((MessageType)1, L.T("Grave emptied - marker removed", "Graven är tömd - markeringen borttagen"), 0, (Sprite)null, false);
					}
				}
			}
			if (flag)
			{
				Save();
			}
		}

		private static void RemoveDeathPin(Vector3 pos)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Minimap instance = Minimap.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			PinData val = null;
			float num = 25f;
			foreach (PinData pin in instance.m_pins)
			{
				if ((int)pin.m_type == 4)
				{
					float num2 = Vector3.Distance(pin.m_pos, pos);
					if (num2 < num)
					{
						num = num2;
						val = pin;
					}
				}
			}
			if (val != null)
			{
				instance.RemovePin(val);
			}
		}

		private static List<Grave> Current(Player player)
		{
			List<Grave> list = new List<Grave>();
			if ((Object)(object)ZNet.instance == (Object)null || (Object)(object)Game.instance == (Object)null)
			{
				return list;
			}
			long playerID = Game.instance.GetPlayerProfile().GetPlayerID();
			string worldName = ZNet.instance.GetWorldName();
			foreach (Grave grafe in Graves)
			{
				if (grafe.PlayerId == playerID && grafe.World == worldName)
				{
					list.Add(grafe);
				}
			}
			return list;
		}

		private static void EnsureLoaded()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			if (_loaded)
			{
				return;
			}
			_loaded = true;
			Graves.Clear();
			try
			{
				if (!File.Exists(FilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(FilePath);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '|' });
					if (array2.Length == 6)
					{
						Graves.Add(new Grave
						{
							PlayerId = long.Parse(array2[0], CultureInfo.InvariantCulture),
							World = array2[1],
							Pos = new Vector3(F(array2[2]), F(array2[3]), F(array2[4])),
							Day = int.Parse(array2[5], CultureInfo.InvariantCulture)
						});
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read the grave list: " + ex.Message));
			}
		}

		private static void Save()
		{
			try
			{
				List<string> list = new List<string>();
				foreach (Grave grafe in Graves)
				{
					list.Add(string.Join("|", grafe.PlayerId.ToString(CultureInfo.InvariantCulture), grafe.World.Replace("|", ""), S(grafe.Pos.x), S(grafe.Pos.y), S(grafe.Pos.z), grafe.Day.ToString(CultureInfo.InvariantCulture)));
				}
				File.WriteAllLines(FilePath, list);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not save the grave list: " + ex.Message));
			}
		}

		private static float F(string s)
		{
			return float.Parse(s, CultureInfo.InvariantCulture);
		}

		private static string S(float f)
		{
			return f.ToString("0.##", CultureInfo.InvariantCulture);
		}
	}
	[HarmonyPatch]
	internal static class ModdedAchievements
	{
		internal static bool ActiveThisSession { get; private set; }

		internal static void CaptureAtStartup()
		{
			ActiveThisSession = Plugin.AchievementsWhenModded.Value;
		}

		[HarmonyPatch(typeof(Achievements), "IsCheatedAtAll")]
		[HarmonyPrefix]
		private static bool Achievements_IsCheatedAtAll(ref bool __result)
		{
			if (!ActiveThisSession)
			{
				return true;
			}
			if (Time.frameCount == Achievements.m_cheatCheckFrame)
			{
				__result = Achievements.m_cheatCheckCache;
				return false;
			}
			Achievements.m_cheatCheckFrame = Time.frameCount;
			bool num = (Object)(object)Game.instance != (Object)null && Game.instance.GetPlayerProfile().m_usedCheats;
			bool flag = Achievements.IsWorldCheated();
			bool flag2 = (Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory().AnyCheatedItem();
			Achievements.m_cheatCheckCache = num || flag || flag2;
			__result = Achievements.m_cheatCheckCache;
			return false;
		}

		internal static void LogState()
		{
			Plugin.Log.LogInfo((object)(ActiveThisSession ? "Achievements in modded game: ON (modded state ignored; cheats still block achievements)." : "Achievements in modded game: OFF (vanilla behaviour)."));
		}

		internal static void OnSettingChanged()
		{
			bool value = Plugin.AchievementsWhenModded.Value;
			Plugin.Log.LogInfo((object)("Achievements in modded game set to " + (value ? "ON" : "OFF") + " - takes effect after a restart."));
			AchievementsMenuButton.UpdateLabel();
			string text = ((value == ActiveThisSession) ? L.T("Achievements when modded: " + (value ? "ON" : "OFF"), "Prestationer i moddat spel: " + (value ? "PÅ" : "AV")) : (value ? L.T("Achievements when modded: ON\nRestart the game for the setting to take effect", "Prestationer i moddat spel: PÅ\nStarta om spelet för att inställningen ska börja gälla") : L.T("Achievements when modded: OFF\nRestart the game for the setting to take effect", "Prestationer i moddat spel: AV\nStarta om spelet för att inställningen ska börja gälla")));
			if ((Object)(object)MessageHud.instance != (Object)null)
			{
				MessageHud.instance.ShowMessage((MessageType)2, text, 0, (Sprite)null, false, true);
			}
		}
	}
	[HarmonyPatch]
	internal static class PinnedRecipes
	{
		internal sealed class Pin
		{
			public Recipe Recipe;

			public Piece Piece;

			public int Quality = 1;

			public bool IsValid
			{
				get
				{
					if (!((Object)(object)Recipe != (Object)null) || !((Object)(object)Recipe.m_item != (Object)null))
					{
						return (Object)(object)Piece != (Object)null;
					}
					return true;
				}
			}

			public string DisplayName => Localization.instance.Localize(((Object)(object)Recipe != (Object)null) ? Recipe.m_item.m_itemData.m_shared.m_name : Piece.m_name);

			public Sprite Icon
			{
				get
				{
					if (!((Object)(object)Recipe != (Object)null))
					{
						return Piece.m_icon;
					}
					return Recipe.m_item.m_itemData.GetIcon();
				}
			}

			public Requirement[] Requirements
			{
				get
				{
					if (!((Object)(object)Recipe != (Object)null))
					{
						return Piece.m_resources;
					}
					return Recipe.m_resources;
				}
			}

			public string Id
			{
				get
				{
					if (!((Object)(object)Recipe != (Object)null))
					{
						return "piece:" + Clean(Utils.GetPrefabName(((Component)Piece).gameObject)) + "@1";
					}
					return Clean(((Object)Recipe).name) + "@" + Quality;
				}
			}

			private static string Clean(string s)
			{
				return s.Replace(";", "").Replace("@", "");
			}
		}

		internal sealed class RecipePinHandler : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
		{
			public Recipe Recipe;

			public int Quality;

			public void OnPointerClick(PointerEventData eventData)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				if ((int)eventData.button == 1)
				{
					Toggle(Recipe, Quality);
				}
			}
		}

		private const string Key = "ValheimSlots.pins";

		private const string PiecePrefix = "piece:";

		private static readonly List<Pin> Pins = new List<Pin>();

		private static Player _owner;

		private static Recipe _crafting;

		private static bool _crafted;

		internal static int Version { get; private set; }

		internal static IReadOnlyList<Pin> All
		{
			get
			{
				EnsureLoaded();
				return Pins;
			}
		}

		internal static bool IsPinned(Recipe recipe)
		{
			EnsureLoaded();
			return Find(recipe) != null;
		}

		internal static void Toggle(Recipe recipe, int quality)
		{
			EnsureLoaded();
			if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && !((Object)(object)_owner == (Object)null))
			{
				Toggle(Find(recipe), new Pin
				{
					Recipe = recipe,
					Quality = Mathf.Max(1, quality)
				});
			}
		}

		internal static void Toggle(Piece piece)
		{
			EnsureLoaded();
			if (!((Object)(object)piece == (Object)null) && !((Object)(object)_owner == (Object)null))
			{
				Toggle(Find(piece), new Pin
				{
					Piece = piece
				});
			}
		}

		private static void Toggle(Pin existing, Pin added)
		{
			if (existing != null)
			{
				Pins.Remove(existing);
				string displayName = existing.DisplayName;
				((Character)_owner).Message((MessageType)1, L.T(displayName + ": unpinned", displayName + ": pin borttagen"), 0, (Sprite)null, false);
			}
			else
			{
				Pins.Add(added);
				string displayName2 = added.DisplayName;
				((Character)_owner).Message((MessageType)1, L.T(displayName2 + ": pinned", displayName2 + ": pinnad"), 0, (Sprite)null, false);
			}
			Changed();
		}

		internal static void HandleBuildMenuInput()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.PinnedEnabled.Value && Hud.IsPieceSelectionVisible() && !((Object)(object)Hud.instance == (Object)null))
			{
				Piece hoveredPiece = Hud.instance.m_hoveredPiece;
				if ((Object)(object)hoveredPiece != (Object)null && SlotController.IsDown(Plugin.PinPieceKey.Value))
				{
					Toggle(hoveredPiece);
				}
			}
		}

		internal static void Remove(Pin pin)
		{
			if (Pins.Remove(pin))
			{
				Changed();
			}
		}

		internal static void ClearAll()
		{
			EnsureLoaded();
			if (Pins.Count != 0)
			{
				Pins.Clear();
				Changed();
				Player owner = _owner;
				if (owner != null)
				{
					((Character)owner).Message((MessageType)1, L.T("All pinned recipes removed", "Alla pinnade recept borttagna"), 0, (Sprite)null, false);
				}
			}
		}

		private static Pin Find(Recipe recipe)
		{
			if ((Object)(object)recipe == (Object)null)
			{
				return null;
			}
			foreach (Pin pin in Pins)
			{
				if ((Object)(object)pin.Recipe != (Object)null && ((Object)(object)pin.Recipe == (Object)(object)recipe || ((Object)pin.Recipe).name == ((Object)recipe).name))
				{
					return pin;
				}
			}
			return null;
		}

		private static Pin Find(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return null;
			}
			string prefabName = Utils.GetPrefabName(((Component)piece).gameObject);
			foreach (Pin pin in Pins)
			{
				if ((Object)(object)pin.Piece != (Object)null && ((Object)(object)pin.Piece == (Object)(object)piece || Utils.GetPrefabName(((Component)pin.Piece).gameObject) == prefabName))
				{
					return pin;
				}
			}
			return null;
		}

		private static void Changed()
		{
			Version++;
			Save();
			if ((Object)(object)InventoryGui.instance != (Object)null && InventoryGui.IsVisible() && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				InventoryGui.instance.UpdateCraftingPanel(false);
			}
		}

		private static void EnsureLoaded()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)(object)_owner)
			{
				return;
			}
			_owner = localPlayer;
			Pins.Clear();
			Version++;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)ObjectDB.instance == (Object)null || !localPlayer.m_customData.TryGetValue("ValheimSlots.pins", out var value) || string.IsNullOrEmpty(value))
			{
				return;
			}
			string[] array = value.Split(new char[1] { ';' });
			foreach (string text in array)
			{
				string[] bits = text.Split(new char[1] { '@' });
				if (bits.Length != 2 || !int.TryParse(bits[1], out var result))
				{
					continue;
				}
				if (bits[0].StartsWith("piece:"))
				{
					GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(bits[0].Substring("piece:".Length)) : null);
					Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
					if ((Object)(object)val2 != (Object)null && Find(val2) == null)
					{
						Pins.Add(new Pin
						{
							Piece = val2
						});
					}
					continue;
				}
				Recipe val3 = ObjectDB.instance.m_recipes.Find((Recipe r) => (Object)(object)r != (Object)null && ((Object)r).name == bits[0]);
				if ((Object)(object)val3 != (Object)null && (Object)(object)val3.m_item != (Object)null && Find(val3) == null)
				{
					Pins.Add(new Pin
					{
						Recipe = val3,
						Quality = result
					});
				}
			}
		}

		private static void Save()
		{
			if ((Object)(object)_owner == (Object)null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Pin pin in Pins)
			{
				if (pin.IsValid)
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(';');
					}
					stringBuilder.Append(pin.Id);
				}
			}
			if (stringBuilder.Length == 0)
			{
				_owner.m_customData.Remove("ValheimSlots.pins");
			}
			else
			{
				_owner.m_customData["ValheimSlots.pins"] = stringBuilder.ToString();
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")]
		[HarmonyPostfix]
		private static void InventoryGui_AddRecipeToList(InventoryGui __instance, Recipe recipe, ItemData item)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.PinnedEnabled.Value && __instance.m_availableRecipes.Count != 0)
			{
				RecipeDataPair val = __instance.m_availableRecipes[__instance.m_availableRecipes.Count - 1];
				GameObject interfaceElement = ((RecipeDataPair)(ref val)).InterfaceElement;
				if (!((Object)(object)interfaceElement == (Object)null))
				{
					RecipePinHandler obj = interfaceElement.GetComponent<RecipePinHandler>() ?? interfaceElement.AddComponent<RecipePinHandler>();
					obj.Recipe = recipe;
					obj.Quality = ((item == null) ? 1 : (item.m_quality + 1));
					PinMarker.Set(interfaceElement.transform, IsPinned(recipe));
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		[HarmonyPrefix]
		private static void InventoryGui_DoCrafting_Prefix(InventoryGui __instance)
		{
			_crafting = __instance.m_craftRecipe;
			_crafted = false;
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(long),
			typeof(string),
			typeof(Vector2i),
			typeof(bool),
			typeof(bool),
			typeof(bool)
		})]
		[HarmonyPostfix]
		private static void Inventory_AddItem_Crafted(string name, ItemData __result)
		{
			if ((Object)(object)_crafting != (Object)null && __result != null && (Object)(object)_crafting.m_item != (Object)null && name == ((Object)((Component)_crafting.m_item).gameObject).name)
			{
				_crafted = true;
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		[HarmonyPostfix]
		private static void Player_TryPlacePiece(Player __instance, Piece piece, bool __result)
		{
			if (!__result || (Object)(object)piece == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			EnsureLoaded();
			Pin pin = Find(piece);
			if (pin != null)
			{
				Pins.Remove(pin);
				Changed();
				string displayName = pin.DisplayName;
				Player owner = _owner;
				if (owner != null)
				{
					((Character)owner).Message((MessageType)1, L.T(displayName + ": built, unpinned", displayName + ": byggd, pin borttagen"), 0, (Sprite)null, false);
				}
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		[HarmonyFinalizer]
		private static void InventoryGui_DoCrafting_Finalizer()
		{
			Recipe crafting = _crafting;
			bool crafted = _crafted;
			_crafting = null;
			_crafted = false;
			if (!crafted || (Object)(object)crafting == (Object)null)
			{
				return;
			}
			EnsureLoaded();
			Pin pin = Find(crafting);
			if (pin != null)
			{
				Pins.Remove(pin);
				Changed();
				string text = Localization.instance.Localize(crafting.m_item.m_itemData.m_shared.m_name);
				Player owner = _owner;
				if (owner != null)
				{
					((Character)owner).Message((MessageType)1, L.T(text + ": done, unpinned", text + ": klar, pin borttagen"), 0, (Sprite)null, false);
				}
			}
		}
	}
	internal static class WeaponSets
	{
		internal static int ActiveSet;

		internal static string SetName(int set)
		{
			if (set != 0)
			{
				return "B";
			}
			return "A";
		}

		internal static void Track(Player player)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			ItemData[] array = (ItemData[])(object)new ItemData[2]
			{
				((Humanoid)player).m_rightItem,
				((Humanoid)player).m_leftItem
			};
			foreach (ItemData val in array)
			{
				if (val != null)
				{
					SlotDef slot = SlotLayout.GetSlot(val.m_gridPos);
					if (slot != null && slot.IsWeapon)
					{
						ActiveSet = slot.Group;
						break;
					}
				}
			}
		}

		internal static void Swap(Player player)
		{
			if (((Character)player).InAttack() || ((Character)player).InDodge() || ((Character)player).IsDead())
			{
				return;
			}
			int num = 1 - ActiveSet;
			Inventory inventory = ((Humanoid)player).m_inventory;
			ItemData val = Get(inventory, SlotKind.WeaponMain, num);
			ItemData val2 = Get(inventory, SlotKind.WeaponOff, num);
			if (val == null && val2 == null)
			{
				((Character)player).Message((MessageType)2, L.T("Weapon set " + SetName(num) + " is empty", "Vapenset " + SetName(num) + " är tomt"), 0, (Sprite)null, false);
				return;
			}
			AutoEquipMove.SuppressDepth++;
			try
			{
				if (((Humanoid)player).m_rightItem != null)
				{
					((Humanoid)player).UnequipItem(((Humanoid)player).m_rightItem, false);
				}
				if (((Humanoid)player).m_leftItem != null)
				{
					((Humanoid)player).UnequipItem(((Humanoid)player).m_leftItem, false);
				}
				if (((Humanoid)player).m_hiddenRightItem != null)
				{
					((Humanoid)player).UnequipItem(((Humanoid)player).m_hiddenRightItem, false);
				}
				if (((Humanoid)player).m_hiddenLeftItem != null)
				{
					((Humanoid)player).UnequipItem(((Humanoid)player).m_hiddenLeftItem, false);
				}
				if (val != null)
				{
					((Humanoid)player).EquipItem(val, true);
				}
				if (val2 != null && (val == null || !SlotLayout.IsTwoHanded(val)))
				{
					((Humanoid)player).EquipItem(val2, true);
				}
			}
			finally
			{
				AutoEquipMove.SuppressDepth--;
			}
			ActiveSet = num;
			((Character)player).Message((MessageType)1, L.T("Weapon set " + SetName(num), "Vapenset " + SetName(num)), 0, (Sprite)null, false);
		}

		private static ItemData Get(Inventory inv, SlotKind kind, int set)
		{
			SlotDef slot = SlotLayout.GetSlot(kind, set);
			if (slot != null)
			{
				return inv.GetItemAt(slot.GridPos.x, slot.GridPos.y);
			}
			return null;
		}
	}
	internal static class L
	{
		private static int _frame = -1;

		private static bool _swedish;

		public static int Version { get; private set; }

		public static bool Swedish
		{
			get
			{
				if (_frame == Time.frameCount)
				{
					return _swedish;
				}
				_frame = Time.frameCount;
				bool flag;
				try
				{
					flag = Localization.instance.GetSelectedLanguage() == "Swedish";
				}
				catch
				{
					flag = false;
				}
				if (flag != _swedish)
				{
					_swedish = flag;
					Version++;
				}
				return _swedish;
			}
		}

		public static string T(string en, string sv)
		{
			if (!Swedish)
			{
				return en;
			}
			return sv;
		}
	}
	internal static class LockedSlots
	{
		private const string Key = "ValheimSlots.locked";

		private static readonly HashSet<Vector2i> Locked = new HashSet<Vector2i>();

		private static Player _owner;

		private static void EnsureLoaded()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)(object)_owner)
			{
				return;
			}
			_owner = localPlayer;
			Locked.Clear();
			if ((Object)(object)localPlayer == (Object)null || !localPlayer.m_customData.TryGetValue("ValheimSlots.locked", out var value) || string.IsNullOrEmpty(value))
			{
				return;
			}
			string[] array = value.Split(new char[1] { ';' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ',' });
				if (array2.Length == 2 && int.TryParse(array2[0], out var result) && int.TryParse(array2[1], out var result2))
				{
					Locked.Add(new Vector2i(result, result2));
				}
			}
		}

		private static void Save()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_owner == (Object)null)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (Vector2i item in Locked)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(';');
				}
				stringBuilder.Append(item.x).Append(',').Append(item.y);
			}
			if (stringBuilder.Length == 0)
			{
				_owner.m_customData.Remove("ValheimSlots.locked");
			}
			else
			{
				_owner.m_customData["ValheimSlots.locked"] = stringBuilder.ToString();
			}
		}

		public static bool IsLocked(Vector2i pos)
		{
			//IL_0000: 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 (!IsOwnLocked(pos))
			{
				if (QuickStackStoreCompat.Active)
				{
					return QuickStackStoreCompat.IsFavoritedSlot(pos);
				}
				return false;
			}
			return true;
		}

		public static bool IsOwnLocked(Vector2i pos)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			EnsureLoaded();
			if (Locked.Count > 0)
			{
				return Locked.Contains(pos);
			}
			return false;
		}

		public static bool Toggle(Vector2i pos)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			EnsureLoaded();
			bool result;
			if (Locked.Remove(pos))
			{
				result = false;
			}
			else
			{
				Locked.Add(pos);
				result = true;
			}
			Save();
			return result;
		}
	}
	[HarmonyPatch]
	internal static class Migration
	{
		private const string VersionKey = "ValheimSlots.version";

		[HarmonyPatch(typeof(Player), "Load")]
		[HarmonyPostfix]
		private static void Player_Load(Player __instance)
		{
			RefreshVanillaRows(__instance);
		}

		[HarmonyPatch(typeof(Player), "EquipInventoryItems")]
		[HarmonyPrefix]
		private static void Player_EquipInventoryItems(Player __instance)
		{
			RefreshVanillaRows(__instance);
		}

		private static void RefreshVanillaRows(Player player)
		{
			if (!((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				string s = default(string);
				SlotLayout.VanillaRows = ((player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result)) ? result : 4);
			}
		}

		public static void Sanitize(Player player)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).m_inventory;
			HashSet<Vector2i> hashSet = new HashSet<Vector2i>();
			List<ItemData> list = new List<ItemData>();
			foreach (ItemData item in inventory.m_inventory)
			{
				if (!SlotLayout.IsValidPlacement(item, item.m_gridPos) || !hashSet.Add(item.m_gridPos))
				{
					list.Add(item);
				}
			}
			if (list.Count == 0)
			{
				player.m_customData["ValheimSlots.version"] = "1.0.8";
				return;
			}
			list.Sort((ItemData a, ItemData b) => Priority(b).CompareTo(Priority(a)));
			List<ItemData> list2 = new List<ItemData>();
			int num = 0;
			foreach (ItemData item2 in list)
			{
				Vector2i val = PreferredSpecialSlot(item2, hashSet);
				if (val.x < 0)
				{
					val = FirstFreeMain(inventory, hashSet);
				}
				if (val.x < 0)
				{
					list2.Add(item2);
					continue;
				}
				Plugin.Log.LogInfo((object)$"Moving {item2.m_shared.m_name} from ({item2.m_gridPos.x},{item2.m_gridPos.y}) to ({val.x},{val.y}).");
				item2.m_gridPos = val;
				hashSet.Add(val);
				num++;
			}
			foreach (ItemData item3 in list2)
			{
				Plugin.Log.LogWarning((object)("Inventory full - dropping " + item3.m_shared.m_name + " at your feet."));
				((Humanoid)player).DropItem(inventory, item3, item3.m_stack);
			}
			if (num > 0 || list2.Count > 0)
			{
				Inv.Changed(inventory);
				((Character)player).Message((MessageType)2, (list2.Count > 0) ? L.T($"ValheimSlots: moved {num} items, {list2.Count} dropped on the ground (inventory full).", $"ValheimSlots: flyttade {num} föremål, {list2.Count} släpptes på marken (fullt).") : L.T($"ValheimSlots: moved {num} items to new slots.", $"ValheimSlots: flyttade {num} föremål till nya platser."), 0, (Sprite)null, false);
			}
			player.m_customData["ValheimSlots.version"] = "1.0.8";
		}

		private static int Priority(ItemData item)
		{
			if (item.m_equipped)
			{
				return 2;
			}
			return (SlotLayout.ArmorSlotFor(item) != null) ? 1 : 0;
		}

		private static Vector2i PreferredSpecialSlot(ItemData item, HashSet<Vector2i> occupied)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			foreach (SlotDef slot in SlotLayout.Slots)
			{
				if (!occupied.Contains(slot.GridPos) && SlotLayout.Fits(slot.Kind, item) && (slot.IsArmor || (slot.IsWeapon && item.m_equipped && slot.Group == 0)))
				{
					return slot.GridPos;
				}
			}
			return new Vector2i(-1, -1);
		}

		private static Vector2i FirstFreeMain(Inventory inv, HashSet<Vector2i> occupied)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			int mainRows = SlotLayout.MainRows;
			Vector2i val = default(Vector2i);
			for (int i = 0; i < mainRows; i++)
			{
				for (int j = 0; j < inv.GetWidth(); j++)
				{
					((Vector2i)(ref val))..ctor(j, i);
					if (!occupied.Contains(val))
					{
						return val;
					}
				}
			}
			return new Vector2i(-1, -1);
		}
	}
	[HarmonyPatch]
	internal static class GuiPatches
	{
		private static bool IsPlayerGrid(InventoryGrid grid)
		{
			if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)grid == (Object)(object)InventoryGui.instance.m_playerGrid)
			{
				return (Object)(object)Player.m_localPlayer != (Object)null;
			}
			return false;
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void InventoryGrid_UpdateGui(InventoryGrid __instance, Player player)
		{
			if (!((Object)(object)player == (Object)null) && IsPlayerGrid(__instance) && __instance.m_inventory == ((Humanoid)player).m_inventory)
			{
				SlotPanel.Layout(__instance, player);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "OnDestroy")]
		[HarmonyPostfix]
		private static void InventoryGui_OnDestroy()
		{
			SlotPanel.Reset();
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		[HarmonyPrefix]
		private static bool InventoryGui_OnSelectedItem_Prefix(InventoryGui __instance, InventoryGrid grid, ItemData item, Vector2i pos)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			AutoEquipMove.SuppressDepth++;
			if ((Object)(object)__instance.m_dragGo == (Object)null || __instance.m_dragItem == null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			if (!DropAllowed(grid.GetInventory(), __instance.m_dragInventory, __instance.m_dragItem, item, pos))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, L.T("That item doesn't fit here", "Det föremålet passar inte här"), 0, (Sprite)null, false);
				return false;
			}
			return true;
		}

		[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
		[HarmonyFinalizer]
		private static void InventoryGui_OnSelectedItem_Finalizer()
		{
			AutoEquipMove.SuppressDepth--;
		}

		[HarmonyPatch(typeof(InventoryGrid), "DropItem")]
		[HarmonyPrefix]
		private static bool InventoryGrid_DropItem(InventoryGrid __instance, Inventory fromInventory, ItemData item, Vector2i pos, ref bool __result)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return true;
			}
			ItemData itemAt = __instance.m_inventory.GetItemAt(pos.x, pos.y);
			if (DropAllowed(__instance.m_inventory, fromInventory, item, itemAt, pos))
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool DropAllowed(Inventory targetInv, Inventory fromInv, ItemData dragged, ItemData target, Vector2i pos)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if (Inv.IsPlayer(targetInv) && !SlotLayout.IsValidPlacement(dragged, pos))
			{
				return false;
			}
			if (target != null && target != dragged && Inv.IsPlayer(fromInv) && IsSwap(dragged, target) && !SlotLayout.IsValidPlacement(target, dragged.m_gridPos))
			{
				return false;
			}
			return true;
		}

		private static bool IsSwap(ItemData dragged, ItemData target)
		{
			if (!(target.m_shared.m_name != dragged.m_shared.m_name) && (dragged.m_shared.m_maxQuality <= 1 || target.m_quality == dragged.m_quality))
			{
				return target.m_shared.m_maxStackSize == 1;
			}
			return true;
		}

		[HarmonyPatch(typeof(Humanoid), "DropItem")]
		[HarmonyPrefix]
		private static void Humanoid_DropItem_Prefix()
		{
			AutoEquipMove.SuppressDepth++;
		}

		[HarmonyPatch(typeof(Humanoid), "DropItem")]
		[HarmonyFinalizer]
		private static void Humanoid_DropItem_Finalizer()
		{
			AutoEquipMove.SuppressDepth--;
		}

		[HarmonyPatch(typeof(InventoryGrid), "OnLeftDown")]
		[HarmonyPrefix]
		private static bool InventoryGrid_OnLeftDown(InventoryGrid __instance, UIInputHandler clickHandler)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if (QuickStackStoreCompat.Active || !IsPlayerGrid(__instance) || (Object)(object)InventoryGui.instance.m_dragGo != (Object)null)
			{
				return true;
			}
			KeyCode value = Plugin.LockModifier.Value;
			if ((int)value == 0 || !ZInput.GetKey(value, false))
			{
				return true;
			}
			Vector2i buttonPos = __instance.GetButtonPos(((Component)clickHandler).gameObject);
			if (!SlotLayout.IsMain(buttonPos))
			{
				return true;
			}
			bool flag = LockedSlots.Toggle(buttonPos);
			((Character)Player.m_localPlayer).Message((MessageType)1, flag ? L.T("Slot locked", "Plats låst") : L.T("Slot unlocked", "Plats upplåst"), 0, (Sprite)null, false);
			return false;
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGamepad")]
		[HarmonyPrefix]
		private static void InventoryGrid_UpdateGamepad_Prefix(InventoryGrid __instance, out Vector2i __state)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			__state = __instance.m_selected;
		}

		[HarmonyPatch(typeof(InventoryGrid), "UpdateGamepad")]
		[HarmonyPostfix]
		private static void InventoryGrid_UpdateGamepad_Postfix(InventoryGrid __instance, Vector2i __state)
		{
			//IL_0009: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_003e: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			if (!IsPlayerGrid(__instance) || __instance.m_selected == __state)
			{
				return;
			}
			Vector2i selected = __instance.m_selected;
			if (SlotLayout.IsMain(selected) || SlotLayout.IsSpecial(selected))
			{
				return;
			}
			bool flag = selected.y > __state.y;
			if (selected.y >= SlotLayout.MainRows && selected.y < 9)
			{
				selected.y = (flag ? 9 : (SlotLayout.MainRows - 1));
			}
			if (selected.y >= 9 && !SlotLayout.IsSpecial(selected))
			{
				for (int num = selected.x; num >= 0; num--)
				{
					if (SlotLayout.IsSpecial(new Vector2i(num, selected.y)))
					{
						selected.x = num;
						break;
					}
				}
			}
			__instance.m_selected = selected;
			RectTransform gamepadSelectedElement = __instance.GetGamepadSelectedElement();
			if ((Object)(object)gamepadSelectedElement != (Object)null)
			{
				Selectable component = ((Component)gamepadSelectedElement).GetComponent<Selectable>();
				if (component != null)
				{
					component.Select();
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class HotkeyBarPatches
	{
		[HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")]
		[HarmonyPostfix]
		[HarmonyPriority(200)]
		private static void HotkeyBar_UpdateIcons(HotkeyBar __instance)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			foreach (ElementData element in __instance.m_elements)
			{
				if (!((Object)(object)element?.m_go == (Object)null))
				{
					bool equipped = element.m_used && (Object)(object)element.m_equiped != (Object)null && element.m_equiped.activeSelf;
					EquippedMarker.Set(element.m_go.transform, equipped, 22f, (Vector2?)new Vector2(2f, 6f));
				}
			}
		}
	}
	internal static class Inv
	{
		public static bool IsPlayer(Inventory inv)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return inv == ((Humanoid)localPlayer).m_inventory;
			}
			return false;
		}

		public static bool IsFreeMainSlot(Inventory inv, int x, int y)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			if (!LockedSlots.IsLocked(new Vector2i(x, y)))
			{
				return inv.GetItemAt(x, y) == null;
			}
			return false;
		}

		public static Vector2i FindFreeMainSlot(Inventory inv, bool topFirst)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			int mainRows = SlotLayout.MainRows;
			int width = inv.GetWidth();
			if (topFirst)
			{
				for (int i = 0; i < mainRows; i++)
				{
					for (int j = 0; j < width; j++)
					{
						if (IsFreeMainSlot(inv, j, i))
						{
							return new Vector2i(j, i);
						}
					}
				}
			}
			else
			{
				for (int num = mainRows - 1; num >= 0; num--)
				{
					for (int k = 0; k < width; k++)
					{
						if (IsFreeMainSlot(inv, k, num))
						{
							return new Vector2i(k, num);
						}
					}
				}
			}
			return new Vector2i(-1, -1);
		}

		public static int CountFreeMainSlots(Inventory inv)
		{
			int num = 0;
			int mainRows = SlotLayout.MainRows;
			int width = inv.GetWidth();
			for (int i = 0; i < mainRows; i++)
			{
				for (int j = 0; j < width; j++)
				{
					if (IsFreeMainSlot(inv, j, i))
					{
						num++;
					}
				}
			}
			return num;
		}

		public static void Changed(Inventory inv)
		{
			inv.Changed(false, false);
		}
	}
	[HarmonyPatch]
	internal static class InventoryPatches
	{
		[HarmonyPatch(typeof(Player), "Awake")]
		[HarmonyPostfix]
		private static void Player_Awake(Player __instance)
		{
			((Humanoid)__instance).m_inventory.SetHeight(12);
		}

		[HarmonyPatch(typeof(Player), "SetInventorySize")]
		[HarmonyPrefix]
		private static bool Player_SetInventorySize(Player __instance, int rows)
		{
			rows = Mathf.Clamp(rows, 0, 9);
			SlotLayout.VanillaRows = rows;
			((Humanoid)__instance).m_inventory.SetHeight(12);
			__instance.AddUniqueKeyValue("invrows", rows.ToString());
			if ((Object)(object)InventoryGui.instance != (Object)null)
			{
				InventoryGui.instance.SetInventorySize(SlotLayout.MainRows);
			}
			SlotLayout.OnLayoutChanged();
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Migration.Sanitize(__instance);
			}
			((Humanoid)__instance).DropInvalidItems();
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "FindEmptySlot")]
		[HarmonyPrefix]
		private static bool Inventory_FindEmptySlot(Inventory __instance, bool topFirst, ref Vector2i __result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (!Inv.IsPlayer(__instance))
			{
				return true;
			}
			__result = Inv.FindFreeMainSlot(__instance, topFirst);
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "HaveEmptySlot")]
		[HarmonyPrefix]
		private static bool Inventory_HaveEmptySlot(Inventory __instance, ref bool __result)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!Inv.IsPlayer(__instance))
			{
				return true;
			}
			__result = Inv.FindFreeMainSlot(__instance, topFirst: true).x >= 0;
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "GetEmptySlots")]
		[HarmonyPrefix]
		private static bool Inventory_GetEmptySlots(Inventory __instance, ref int __result)
		{
			if (!Inv.IsPlayer(__instance))
			{
				return true;
			}
			__result = Inv.CountFreeMainSlots(__instance);
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		[HarmonyPrefix]
		private static bool Inventory_CanAddItem(Inventory __instance, ItemData item, int stack, ref bool __result)
		{
			if (!Inv.IsPlayer(__instance))
			{
				return true;
			}
			if (stack <= 0)
			{
				stack = item.m_stack;
			}
			__result = __instance.FindFreeStackSpace(item.m_shared.m_name, (float)item.m_worldLevel) + Inv.CountFreeMainSlots(__instance) * item.m_shared.m_maxStackSize >= stack;
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static bool Inventory_AddItemAt(Inventory __instance, ItemData item, int x, int y, bool skipValidPositionCheck, ref bool __result)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (skipValidPositionCheck || !Inv.IsPlayer(__instance))
			{
				return true;
			}
			if (SlotLayout.IsValidPlacement(item, new Vector2i(x, y)))
			{
				return true;
			}
			__result = false;
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(Vector2i)
		})]
		[HarmonyPrefix]
		private static bool Inventory_AddItemAtPos(Inventory __instance, ItemData item, Vector2i pos, ref bool __result)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!Inv.IsPlayer(__instance) || SlotLayout.IsValidPlacement(item, pos))
			{
				return true;
			}
			__result = __instance.AddItem(item);
			return false;
		}

		[HarmonyPatch(typeof(Inventory), "StackAll")]
		[HarmonyPrefix]
		private static void Inventory_StackAll_Prefix(Inventory fromInventory, out List<ItemData> __state)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			__state = null;
			if (!Inv.IsPlayer(fromInventory))
			{
				return;
			}
			foreach (ItemData item in fromInventory.m_inventory)
			{
				if (SlotLayout.IsReserved(item.m_gridPos) || LockedSlots.IsLocked(item.m_gridPos))
				{
					(__state ?? (__state = new List<ItemData>())).Add(item);
				}
			}
			if (__state != null)
			{
				fromInventory.m_inventory.RemoveAll(__state.Contains);
			}
		}

		[HarmonyPatch(typeof(Inventory), "StackAll")]
		[HarmonyFinalizer]
		private static void Inventory_StackAll_Finalizer(Inventory fromInventory, List<ItemData> __state)
		{
			if (__state != null)
			{
				fromInventory.m_inventory.AddRange(__state);
				Inv.Changed(fromInventory);
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveOneItem")]
		[HarmonyPrefix]
		private static void Inventory_RemoveOneItem(Inventory __instance, ItemData item)
		{
			if (item != null && item.m_stack <= 1 && Inv.IsPlayer(__instance))
			{
				AutoRefill.NotifyEmptying(item);
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		[HarmonyPrefix]
		private static void Inventory_RemoveItemAmount(Inventory __instance, ItemData item, int amount)
		{
			if (item != null && amount >= item.m_stack && Inv.IsPlayer(__instance))
			{
				AutoRefill.NotifyEmptying(item);
			}
		}
	}
	[HarmonyPatch]
	internal static class TombstonePatches
	{
		[HarmonyPatch(typeof(TombStone), "EasyFitInInventory")]
		[HarmonyPostfix]
		private static void TombStone_EasyFitInInventory(TombStone __instance, Player player, ref bool __result)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (__result || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			Inventory inventory = __instance.m_container.GetInventory();
			Inventory inventory2 = ((Humanoid)player).GetInventory();
			if (inventory2.GetTotalWeight() + inventory.GetTotalWeight() > player.GetMaxCarryWeight())
			{
				return;
			}
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				Vector2i gridPos = allItem.m_gridPos;
				if ((!SlotLayout.IsValidPlacement(allItem, gridPos) || inventory2.GetItemAt(gridPos.x, gridPos.y) != null || LockedSlots.IsLocked(gridPos)) && inventory2.FindFreeStackSpace(allItem.m_shared.m_name, (float)allItem.m_worldLevel) < allItem.m_stack)
				{
					num++;
				}
			}
			__result = num <= Inv.CountFreeMainSlots(inventory2);
		}
	}
	[BepInPlugin("lorcisen.valheimslots", "ValheimSlots", "1.0.8")]
	[BepInIncompatibility("randyknapp.mods.equipmentandquickslots")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Author = "Lorcisen";

		public const string Guid = "lorcisen.valheimslots";

		public const string Name = "ValheimSlots";

		private const string OldGuid = "pelle.valheimslots";

		public const string Version = "1.0.8";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal static ConfigEntry<int> MainRows;

		internal static ConfigEntry<Vector2> PanelPosition;

		internal static ConfigEntry<bool> ShowEquippedMarker;

		internal static ConfigEntry<KeyboardShortcut>[] FoodKeys;

		internal static ConfigEntry<KeyboardShortcut>[] MeadKeys;

		internal static ConfigEntry<KeyboardShortcut>[] AmmoKeys;

		internal static ConfigEntry<KeyboardShortcut> WeaponSetKey;

		internal static ConfigEntry<KeyCode> LockModifier;

		internal static ConfigEntry<bool> AutoMoveWeapons;

		internal static ConfigEntry<bool> AutoRefill;

		internal static ConfigEntry<bool> TopUpFromInventory;

		internal static ConfigEntry<bool> AutoEat;

		internal static ConfigEntry<int> AutoEatSecondsLeft;

		internal static ConfigEntry<bool> AchievementsWhenModded;

		internal static ConfigEntry<bool> AutoClearCheated;

		internal static ConfigEntry<KeyboardShortcut> ClearCheatedKey;

		internal static ConfigEntry<bool> AutoRepair;

		internal static ConfigEntry<float> AutoRepairDistance;

		internal static ConfigEntry<bool> CraftSearch;

		internal static ConfigEntry<bool> ShowGraveArrow;

		internal static ConfigEntry<bool> ShowPortalWarning;

		internal static ConfigEntry<bool> PinnedEnabled;

		internal static ConfigEntry<Vector2> PinnedPosition;

		internal static ConfigEntry<int> PinnedMaxShown;

		internal static ConfigEntry<KeyboardShortcut> ClearPinsKey;

		internal static ConfigEntry<KeyboardShortcut> PinPieceKey;

		internal static ConfigEntry<bool> ShowHud;

		internal static ConfigEntry<Vector2> HudPosition;

		internal static ConfigEntry<bool> ShowWeight;

		internal static ConfigEntry<int> DurabilityWarnPercent;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			if (Application.isBatchMode || (int)SystemInfo.graphicsDeviceType == 4)
			{
				Log.LogInfo((object)"Dedicated server detected - ValheimSlots is a client-side mod and does nothing here.");
				return;
			}
			MigrateOldConfigFile();
			BindConfig();
			ModdedAchievements.CaptureAtStartup();
			_harmony = new Harmony("lorcisen.valheimslots");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			QuickStackStoreCompat.TryPatch(_harmony);
			((Component)this).gameObject.AddComponent<SlotController>();
			ModdedAchievements.LogState();
			Log.LogInfo((object)string.Format("{0} {1} loaded. Main inventory: {2} rows, special slots on rows {3}-{4}.", "ValheimSlots", "1.0.8", MainRows.Value, 9, 11));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void MigrateOldConfigFile()
		{
			try
			{
				string text = Path.Combine(Paths.ConfigPath, "pelle.valheimslots.cfg");
				if (File.Exists(text) && !File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
				{
					File.Move(text, ((BaseUnityPlugin)this).Config.ConfigFilePath);
					((BaseUnityPlugin)this).Config.Reload();
					Log.LogInfo((object)"Moved settings from pelle.valheimslots.cfg to lorcisen.valheimslots.cfg.");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Could not move old settings: " + ex.Message));
			}
		}

		private void BindConfig()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Expected O, but got Unknown
			//IL_0478: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0502: Expected O, but got Unknown
			//IL_05c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0614: Unknown result type (might be due to invalid IL or missing references)
			//IL_061e: Expected O, but got Unknown
			//IL_0646: Unknown result type (might be due to invalid IL or missing references)
			//IL_067e: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0756: Unknown result type (might be due to invalid IL or missing references)
			//IL_0760: Expected O, but got Unknown
			//IL_076a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0779: Unknown result type (might be due to invalid IL or missing references)
			//IL_07a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_07b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0794: Unknown result type (might be due to invalid IL or missing references)
			//IL_07cd: Unknown result type (might be due to invalid IL or missing references)
			MainRows = ((BaseUnityPlugin)this).Config.Bind<int>("1 - Inventory", "Main rows", 6, new ConfigDescription(L.T("Number of rows in the main inventory (vanilla is 4). If you bought more rows in game, the higher value is used.", "Antal rader i huvudinventoryt (vanilla är 4). Om du köpt fler rader i spelet används det högre värdet."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 9), Array.Empty<object>()));
			PanelPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("2 - Panel", "Panel position", new Vector2(740f, 28f), L.T("Position of the special slot panel relative to the inventory's top-left corner. Increase X if the panel covers other buttons.", "Specialpanelens position relativt inventoryts övre vänstra hörn. Öka X om panelen täcker andra knappar."));
			ShowEquippedMarker = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Panel", "Show equipped check mark", true, L.T("Show a white check mark on equipped items (easier to see than the color highlight, e.g. for color blindness).", "Visa en vit bock på utrustade föremål (lättare att se än färgmarkeringen, t.ex. vid färgblindhet)."));
			FoodKeys = new ConfigEntry<KeyboardShortcut>[3]
			{
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Food 1", new KeyboardShortcut((KeyCode)122, Array.Empty<KeyCode>()), L.T("Eat the food in food slot 1.", "Ät maten i matplats 1.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Food 2", new KeyboardShortcut((KeyCode)98, Array.Empty<KeyCode>()), L.T("Eat the food in food slot 2.", "Ät maten i matplats 2.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Food 3", new KeyboardShortcut((KeyCode)110, Array.Empty<KeyCode>()), L.T("Eat the food in food slot 3.", "Ät maten i matplats 3."))
			};
			MeadKeys = new ConfigEntry<KeyboardShortcut>[3]
			{
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Mead 1", new KeyboardShortcut((KeyCode)57, Array.Empty<KeyCode>()), L.T("Drink the mead/potion in slot 1.", "Drick mjöd/dryck i plats 1.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Mead 2", new KeyboardShortcut((KeyCode)48, Array.Empty<KeyCode>()), L.T("Drink the mead/potion in slot 2.", "Drick mjöd/dryck i plats 2.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Mead 3", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), L.T("Drink the mead/potion in slot 3.", "Drick mjöd/dryck i plats 3."))
			};
			AmmoKeys = new ConfigEntry<KeyboardShortcut>[3]
			{
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Ammo 1", new KeyboardShortcut((KeyCode)117, Array.Empty<KeyCode>()), L.T("Select the ammo in ammo slot 1.", "Välj ammo i ammoplats 1.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Ammo 2", new KeyboardShortcut((KeyCode)105, Array.Empty<KeyCode>()), L.T("Select the ammo in ammo slot 2.", "Välj ammo i ammoplats 2.")),
				((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Ammo 3", new KeyboardShortcut((KeyCode)121, Array.Empty<KeyCode>()), L.T("Select the ammo in ammo slot 3.", "Välj ammo i ammoplats 3."))
			};
			WeaponSetKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("3 - Hotkeys", "Swap weapon set", new KeyboardShortcut((KeyCode)301, Array.Empty<KeyCode>()), L.T("Swap between weapon set A and B.", "Byt mellan vapenset A och B."));
			LockModifier = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("3 - Hotkeys", "Lock slot modifier", (KeyCode)308, L.T("Hold this key and left-click a slot to lock it. If Quick Stack - Store - Sort is installed, its favorite marking (also Alt+click) is used as the lock instead.", "Håll in denna tangent och vänsterklicka på en plats för att låsa den. Om Quick Stack - Store - Sort är installerat används dess favoritmarkering (också Alt+klick) som lås i stället."));
			AutoMoveWeapons = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Hotkeys", "Auto move weapons to set", true, L.T("Move weapons into the active weapon set when you equip them from the main inventory (not from the 1-8 hotbar).", "Flytta vapen till aktivt vapenset när du utrustar dem från huvudinventoryt (inte från hotbaren 1-8)."));
			AutoRefill = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Auto", "Auto refill", true, L.T("Refill food, mead and ammo slots from the inventory when a stack runs out.", "Fyll på mat-, mjöd- och ammoplatser från inventoryt när en stack tar slut."));
			TopUpFromInventory = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Auto", "Top up stacks", true, L.T("Top up partial stacks in food, mead and ammo slots from the inventory (while the inventory is closed).", "Fyll på ofullständiga stackar i mat-, mjöd- och ammoplatser från inventoryt (när inventoryt är stängt)."));
			AutoEat = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Auto", "Auto eat", false, L.T("Eat automatically from the food slots when a food buff is running out or a food slot in your stomach is free.", "Ät automatiskt från matplatserna när en matbuff håller på att ta slut eller en matplats i magen är ledig."));
			AutoEatSecondsLeft = ((BaseUnityPlugin)this).Config.Bind<int>("4 - Auto", "Auto eat seconds left", 60, new ConfigDescription(L.T("Eat again when this many seconds of a food buff remain.", "Ät igen när så här många sekunder återstår av en matbuff."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(5, 1200), Array.Empty<object>()));
			AchievementsWhenModded = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Cheat flag", "Achievements when modded", false, L.T("Allow achievements even though the game is modded. Only the modded state is ignored - cheat commands, cheat world modifiers and cheated items still block achievements. Off = normal Valheim behaviour. Can also be toggled in the pause menu (Esc). Takes effect after restarting the game.", "Tillåt prestationer trots att spelet är moddat. Bara moddningen ignoreras - fuskkommandon, fusk-världsinställningar och fuskmarkerade föremål spärrar fortfarande. Av = vanligt Valheim-beteende. Kan också slås på/av i pausmenyn (Esc). Gäller efter omstart av spelet."));
			AchievementsWhenModded.SettingChanged += delegate
			{
				ModdedAchievements.OnSettingChanged();
			};
			AutoClearCheated = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Cheat flag", "Auto clear inventory", true, L.T("Automatically remove \"summoned through cheating means\" from items in your inventory. Achievements are already disabled in a modded game, so the flag has no function - it only spreads.", "Ta automatiskt bort \"summoned through cheating means\" från föremål i ditt inventory. I ett moddat spel är prestationer redan avstängda, så markeringen har ingen funktion - den sprider sig bara."));
			ClearCheatedKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("6 - Cheat flag", "Clear nearby key", new KeyboardShortcut((KeyCode)290, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), L.T("Remove the flag from your inventory, your character, and buildings/workbenches and chests within 30 m.", "Ta bort markeringen från inventoryt, karaktären samt byggnader/arbetsbänkar och kistor inom 30 m."));
			AutoRepair = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Convenience", "Auto repair", true, L.T("Automatically repair everything a nearby workbench, forge etc. can repair (same rules as the repair button).", "Reparera automatiskt allt som en närliggande arbetsbänk, smedja osv. kan reparera (samma regler som reparationsknappen)."));
			AutoRepairDistance = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Convenience", "Auto repair distance", 5f, new ConfigDescription(L.T("How close to the station you need to be (meters).", "Hur nära stationen du måste vara (meter)."), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), Array.Empty<object>()));
			CraftSearch = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Convenience", "Recipe search", true, L.T("Show a search field above the recipe list. Start with ! to search by ingredient (e.g. !iron).", "Visa ett sökfält ovanför receptlistan. Börja med ! för att söka på ingrediens (t.ex. !järn)."));
			ShowGraveArrow = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Convenience", "Grave arrow", true, L.T("Show an arrow and the distance to your grave. The grave and map marker are removed once the grave is emptied.", "Visa en pil och avståndet till din grav. Grav- och kartmarkeringen tas bort när graven är tömd."));
			ShowPortalWarning = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Convenience", "Portal warning", true, L.T("Show how many carried items can't go through a portal (ore, metal etc.).", "Visa hur många föremål du bär som inte får tas genom en portal (malm, metall m.m.)."));
			PinnedEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Pinned recipes", "Enabled", true, L.T("Right-click a recipe in the crafting list to pin it. Pinned recipes are shown on the right with the ingredients you need.", "Högerklicka på ett recept i tillverkningslistan för att pinna det. Pinnade recept visas till höger med ingredienserna du behöver."));
			PinnedPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("8 - Pinned recipes", "Position", new Vector2(-20f, 120f), L.T("Top-right corner of the list, relative to the right edge of the screen (vertical middle). Negative X = in from the edge, positive Y = up.", "Listans övre högra hörn, relativt skärmens högra kant (mitten i höjdled). Negativt X = in från kanten, positivt Y = uppåt."));
			PinnedMaxShown = ((BaseUnityPlugin)this).Config.Bind<int>("8 - Pinned recipes", "Max shown", 5, new ConfigDescription(L.T("How many pinned recipes are shown at once.", "Hur många pinnade recept som visas samtidigt."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 15), Array.Empty<object>()));
			ClearPinsKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("8 - Pinned recipes", "Clear all key", new KeyboardShortcut((KeyCode)292, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), L.T("Remove all pinned recipes.", "Ta bort alla pinnade recept."));
			PinPieceKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("8 - Pinned recipes", "Pin build piece key", new KeyboardShortcut((KeyCode)325, Array.Empty<KeyCode>()), L.T("Press while hovering a piece in the build menu (hammer, cultivator, ...) to pin or unpin it. Default: middle mouse button.", "Tryck medan du håller musen över en byggbit i byggmenyn (hammare, kultivator, ...) för att pinna eller ta bort den. Standard: mittenklick (scrollhjulet)."));
			ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - HUD", "Show quick slot HUD", true, L.T("Show the food, mead and ammo slots on screen.", "Visa mat-, mjöd- och ammoplatserna på skärmen."));
			HudPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("5 - HUD", "HUD position", new Vector2(0f, 230f), L.T("Position of the HUD relative to the bottom center of the screen.", "Position för HUD:en relativt skärmens nederkant (mitten)."));
			ShowWeight = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - HUD", "Show weight", true, L.T("Show carry weight (current/max) above the quick slots.", "Visa vikt (nu/max) ovanför snabbplatserna."));
			DurabilityWarnPercent = ((BaseUnityPlugin)this).Config.Bind<int>("5 - HUD", "Durability warning percent", 20, new ConfigDescription(L.T("Warn when equipped gear has less durability than this (0 = off).", "Varna när utrustad utrustning har mindre hållbarhet än så här (0 = av)."), (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
			if (PanelPosition.Value == new Vector2(615f, 28f))
			{
				PanelPosition.Value = (Vector2)((ConfigEntryBase)PanelPosition).DefaultValue;
			}
			if (HudPosition.Value == new Vector2(0f, 150f))
			{
				HudPosition.Value = (Vector2)((ConfigEntryBase)HudPosition).DefaultValue;
			}
			((BaseUnityPlugin)this).Config.Save();
			MainRows.SettingChanged += delegate
			{
				SlotLayout.OnLayoutChanged();
			};
		}
	}
	internal sealed class SlotController : MonoBehaviour
	{
		private float _nextRefill;

		private float _nextEat;

		private void Update()
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				WeaponSets.Track(localPlayer);
				if (((Character)localPlayer).TakeInput())
				{
					HandleHotkeys(localPlayer);
				}
				PinnedRecipes.HandleBuildMenuInput();
				float time = Time.time;
				if (time >= _nextRefill)
				{
					_nextRefill = time + 0.25f;
					AutoRefill.Tick(localPlayer);
				}
				if (time >= _nextEat)
				{
					_nextEat = time + 1f;
					AutoRefill.AutoEat(localPlayer);
				}
				CheatCleaner.Tick(localPlayer);
				AutoRepair.Tick(localPlayer);
				GraveTracker.Tick(localPlayer);
				StatusHud.Update(localPlayer);
				PinnedPanel.Update(localPlayer);
			}
		}

		private static void HandleHotkeys(Player player)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (IsDown(Plugin.WeaponSetKey.Value))
			{
				WeaponSets.Swap(player);
			}
			if (IsDown(Plugin.ClearCheatedKey.Value))
			{
				CheatCleaner.ClearAround(player);
			}
			if (IsDown(Plugin.ClearPinsKey.Value))
			{
				PinnedRecipes.ClearAll();
			}
			for (int i = 0; i < 3; i++)
			{
				if (IsDown(Plugin.FoodKeys[i].Value))
				{
					UseSlot(player, SlotKind.Food, i);
				}
				if (IsDown(Plugin.MeadKeys[i].Value))
				{
					UseSlot(player, SlotKind.Mead, i);
				}
				if (IsDown(Plugin.AmmoKeys[i].Value))
				{
					UseSlot(player, SlotKind.Ammo, i);
				}
			}
		}

		private static void UseSlot(Player player, SlotKind kind, int group)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Invalid comparison between Unknown and I4
			SlotDef slot = SlotLayout.GetSlot(kind, group);
			if (slot == null)
			{
				return;
			}
			ItemData itemAt = ((Humanoid)player).m_inventory.GetItemAt(slot.GridPos.x, slot.GridPos.y);
			if (itemAt == null)
			{
				((Character)player).Message((MessageType)1, L.T("The slot is empty", "Platsen är tom"), 0, (Sprite)null, false);
			}
			else if (kind == SlotKind.Ammo)
			{
				if ((int)itemAt.m_shared.m_itemType == 9 && !((Humanoid)player).IsItemEquiped(itemAt))
				{
					((Humanoid)player).EquipItem(itemAt, true);
				}
			}
			else
			{
				((Humanoid)player).UseItem(((Humanoid)player).m_inventory, itemAt, false);
			}
		}

		internal static bool IsDown(KeyboardShortcut shortcut)
		{
			//IL_0002: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey, false))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}
	}
	internal enum SlotKind
	{
		Helmet,
		Chest,
		Legs,
		Cape,
		Utility,
		Trinket,
		WeaponMain,
		WeaponOff,
		Ammo,
		Food,
		Mead
	}
	internal sealed class SlotDef
	{
		public readonly int Index;

		public readonly SlotKind Kind;

		public readonly Vector2i GridPos;

		public readonly Vector2i PanelCell;

		private readonly string _labelEn;

		private readonly string _labelSv;

		public readonly int Group;

		public string Label => L.T(_labelEn, _labelSv);

		public bool IsRefillable
		{
			get
			{
				if (Kind != SlotKind.Ammo && Kind != SlotKind.Food)
				{
					return Kind == SlotKind.Mead;
				}
				return true;
			}
		}

		public bool IsArmor => Kind <= SlotKind.Trinket;

		public bool IsWeapon
		{
			get
			{
				if (Kind != SlotKind.WeaponMain)
				{
					return Kind == SlotKind.WeaponOff;
				}
				return true;
			}
		}

		public SlotDef(int index, SlotKind kind, Vector2i gridPos, Vector2i panelCell, string labelEn, string labelSv, int group = 0)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			Index = index;
			Kind = kind;
			GridPos = gridPos;
			PanelCell = panelCell;
			_labelEn = labelEn;
			_labelSv = labelSv;
			Group = group;
		}
	}
	internal static class SlotLayout
	{
		public const int Width = 8;

		public const int MaxVanillaRows = 9;

		public const int SpecialStartRow = 9;

		public const int SpecialRows = 3;

		public const int TotalRows = 12;

		public static int VanillaRows;

		public static readonly List<SlotDef> Slots;

		private static readonly Dictionary<Vector2i, SlotDef> ByPos;

		public static int MainRows => Mathf.Clamp(Mathf.Max(Plugin.MainRows?.Value ?? 6, VanillaRows), 1, 9);

		public static int LayoutVersion { get; private set; }

		static SlotLayout()
		{
			VanillaRows = 4;
			Slots = new List<SlotDef>();
			ByPos = new Dictionary<Vector2i, SlotDef>();
			int y = 9;
			int y2 = 10;
			int y3 = 11;
			Add(SlotKind.Helmet, 0, y, 0, 0, "Helmet", "Hjälm");
			Add(SlotKind.Chest, 1, y, 1, 0, "Chest", "Bröst");
			Add(SlotKind.Legs, 2, y, 2, 0, "Legs", "Ben");
			Add(SlotKind.Cape, 3, y, 3, 0, "Cape", "Mantel");
			Add(SlotKind.Utility, 4, y, 0, 1, "Belt", "Bälte");
			Add(SlotKind.Trinket, 5, y, 1, 1, "Trinket", "Trinket");
			Add(SlotKind.WeaponMain, 0, y2, 0, 2, "A", "A");
			Add(SlotKind.WeaponOff, 1, y2, 1, 2, "A", "A");
			Add(SlotKind.WeaponMain, 2, y2, 2, 2, "B", "B", 1);
			Add(SlotKind.WeaponOff, 3, y2, 3, 2, "B", "B", 1);
			Add(SlotKind.Ammo, 4, y2, 0, 3, "", "");
			Add(SlotKind.Ammo, 5, y2, 1, 3, "", "", 1);
			Add(SlotKind.Ammo, 6, y2, 2, 3, "", "", 2);
			Add(SlotKind.Food, 0, y3, 0, 4, "", "");
			Add(SlotKind.Food, 1, y3, 1, 4, "", "", 1);
			Add(SlotKind.Food, 2, y3, 2, 4, "", "", 2);
			Add(SlotKind.Mead, 3, y3, 0, 5, "", "");
			Add(SlotKind.Mead, 4, y3, 1, 5, "", "", 1);
			Add(SlotKind.Mead, 5, y3, 2, 5, "", "", 2);
		}

		private static void Add(SlotKind kind, int x, int y, int col, int row, string labelEn, string labelSv, int group = 0)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			SlotDef slotDef = new SlotDef(Slots.Count, kind, new Vector2i(x, y), new Vector2i(col, row), labelEn, labelSv, group);
			Slots.Add(slotDef);
			ByPos[slotDef.GridPos] = slotDef;
		}

		public static void OnLayoutChanged()
		{
			LayoutVersion++;
		}

		public static SlotDef GetSlot(Vector2i pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (!ByPos.TryGetValue(pos, out var value))
			{
				return null;
			}
			return value;
		}

		public static SlotDef GetSlot(SlotKind kind, int group)
		{
			foreach (SlotDef slot in Slots)
			{
				if (slot.Kind == kind && slot.Group == group)
				{
					return slot;
				}
			}
			return null;
		}

		public static bool IsMain(Vector2i pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (pos.x >= 0 && pos.x < 8 && pos.y >= 0)
			{
				return pos.y < MainRows;
			}
			return false;
		}

		public static bool IsSpecial(Vector2i pos)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return ByPos.ContainsKey(pos);
		}

		public static bool IsReserved(Vector2i pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return !IsMain(pos);
		}

		public static bool IsValidPlacement(ItemData item, Vector2i pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (IsMain(pos))
			{
				return true;
			}
			SlotDef slot = GetSlot(pos);
			if (slot != null && item != null)
			{
				return Fits(slot.Kind, item);
			}
			return false;
		}

		public static bool IsFood(ItemData item)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			SharedData shared = item.m_shared;
			if ((int)shared.m_itemType == 2)
			{
				if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f))
				{
					return shared.m_foodEitr > 0f;
				}
				return true;
			}
			return false;
		}

		public static bool Fits(SlotKind kind, 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Invalid comparison between Unknown and I4
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Invalid comparison between Unknown and I4
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Invalid comparison between Unknown and I4
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Invalid comparison between Unknown and I4
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Invalid comparison between Unknown and I4
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Invalid comparison between Unknown and I4
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Invalid comparison between Unknown and I4
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Invalid comparison between Unknown a