Decompiled source of GearAndStorage v0.5.7

plugins/GearAndStorage/GearAndStorage.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
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 GearAndStorage.Core;
using HarmonyLib;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("GearAndStorage")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.7.0")]
[assembly: AssemblyInformationalVersion("0.5.7")]
[assembly: AssemblyProduct("GearAndStorage")]
[assembly: AssemblyTitle("GearAndStorage")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.5.7.0")]
[module: UnverifiableCode]
namespace GearAndStorage
{
	internal static class ChestCrafting
	{
		[HarmonyPatch(typeof(Container), "Awake")]
		private static class Register
		{
			private static void Postfix(Container __instance)
			{
				if (__instance.m_inventory != null)
				{
					Containers.Add(__instance);
					nextScan = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
		private static class Requirements
		{
			private static void Prefix(Player __instance, bool discover, out bool __state)
			{
				__state = !discover && Enter(__instance);
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "GetFirstRequiredItem")]
		private static class OneIngredient
		{
			private static void Prefix(Player __instance, out bool __state)
			{
				__state = Enter(__instance);
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
		private static class RequirementLabel
		{
			private static void Prefix(Player player, bool craft, out bool __state)
			{
				__state = Enter(player);
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
		private static class Craft
		{
			private static void Prefix(Player player, out bool __state)
			{
				__state = Enter(player, force: true);
				if (__state)
				{
					craftingDepth++;
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					craftingDepth--;
				}
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
		{
			typeof(Piece),
			typeof(RequirementMode)
		})]
		private static class BuildRequirements
		{
			private static void Prefix(Player __instance, RequirementMode mode, out bool __state)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0003: Invalid comparison between Unknown and I4
				__state = (int)mode != 1 && Enter(__instance);
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class Build
		{
			private static void Prefix(Player __instance, bool takeInput, out bool __state)
			{
				__state = takeInput && ((Character)__instance).InPlaceMode() && Enter(__instance);
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class Place
		{
			private static bool Prefix(Player __instance, Piece piece, ref bool __result, out bool __state)
			{
				//IL_001b: Unknown result type (might be due to invalid IL or missing references)
				__state = Enter(__instance, force: true);
				if (__state && !__instance.m_noPlacementCost && !ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey()) && !__instance.HaveRequirements(piece, (RequirementMode)0))
				{
					__result = false;
					return false;
				}
				return true;
			}

			private static void Finalizer(bool __state)
			{
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static class Consume
		{
			private static void Prefix(Player __instance, out bool __state)
			{
				__state = !__instance.m_noPlacementCost && Enter(__instance, queryDepth == 0);
				if (__state)
				{
					craftingDepth++;
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					craftingDepth--;
				}
				Exit(__state);
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static class HaveMaterial
		{
			private static void Postfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
			{
				if (__result || !Query(__instance))
				{
					return;
				}
				foreach (Container source in sources)
				{
					if (Accessible(source, Player.m_localPlayer) && source.m_inventory.HaveItem(name, matchWorldLevel))
					{
						__result = true;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "CountItems")]
		private static class Count
		{
			private static void Postfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
			{
				if (!Query(__instance))
				{
					return;
				}
				foreach (Container source in sources)
				{
					if (Accessible(source, Player.m_localPlayer))
					{
						__result += source.m_inventory.CountItems(name, quality, matchWorldLevel);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "GetItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(bool)
		})]
		private static class Lookup
		{
			private static void Postfix(Inventory __instance, string name, int quality, bool isPrefabName, ref ItemData __result)
			{
				if (__result != null || !Query(__instance))
				{
					return;
				}
				foreach (Container source in sources)
				{
					if (Accessible(source, Player.m_localPlayer))
					{
						__result = source.m_inventory.GetItem(name, quality, isPrefabName);
						if (__result != null)
						{
							break;
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "ItemCheated", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(bool)
		})]
		private static class CheatedIngredients
		{
			private static void Postfix(Inventory __instance, string itemName, int quality, bool matchWorldLevel, ref bool __result)
			{
				if (__result || !Query(__instance))
				{
					return;
				}
				foreach (Container source in sources)
				{
					if (Accessible(source, Player.m_localPlayer) && source.m_inventory.ItemCheated(itemName, quality, matchWorldLevel))
					{
						__result = true;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "ItemCheated", new Type[]
		{
			typeof(Requirement[]),
			typeof(int),
			typeof(bool)
		})]
		private static class CheatedRecipe
		{
			private static void Postfix(Inventory __instance, Requirement[] resources, int quality, bool matchWorldLevel, ref bool __result)
			{
				if (__result || !Query(__instance))
				{
					return;
				}
				foreach (Container source in sources)
				{
					if (Accessible(source, Player.m_localPlayer) && source.m_inventory.ItemCheated(resources, quality, matchWorldLevel))
					{
						__result = true;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
		{
			typeof(string),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class Payment
		{
			private static bool Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased)
			{
				if (craftingDepth == 0 || !Query(__instance))
				{
					return true;
				}
				List<Inventory> list = new List<Inventory>();
				list.Add(__instance);
				list.AddRange(from c in sources
					where Accessible(c, Player.m_localPlayer)
					select c.m_inventory);
				List<Tuple<Inventory, ItemData>> list2 = new List<Tuple<Inventory, ItemData>>();
				foreach (Inventory item2 in list)
				{
					foreach (ItemData allItem in item2.GetAllItems())
					{
						if (!(allItem.m_shared.m_name != name) && (itemQuality < 0 || allItem.m_quality == itemQuality) && (!worldLevelBased || allItem.m_worldLevel >= Game.m_worldLevel))
						{
							list2.Add(Tuple.Create<Inventory, ItemData>(item2, allItem));
						}
					}
				}
				int[] array = PaymentPlanner.Allocate(list2.Select((Tuple<Inventory, ItemData> entry) => entry.Item2.m_stack).ToArray(), amount);
				if (array == null)
				{
					throw new InvalidOperationException("GearAndStorage: crafting materials changed during native crafting; payment aborted.");
				}
				HashSet<Inventory> hashSet = new HashSet<Inventory>();
				for (int num = 0; num < array.Length; num++)
				{
					if (array[num] != 0)
					{
						ItemData item = list2[num].Item2;
						item.m_stack -= array[num];
						hashSet.Add(list2[num].Item1);
					}
				}
				foreach (Inventory item3 in hashSet)
				{
					item3.m_inventory.RemoveAll((ItemData val) => val.m_stack <= 0);
				}
				foreach (Inventory item4 in hashSet)
				{
					item4.Changed(false, false);
				}
				return false;
			}
		}

		private static ConfigEntry<bool> Enabled;

		private static ConfigEntry<float> Radius;

		private static readonly HashSet<Container> Containers = new HashSet<Container>();

		private static List<Container> nearby = new List<Container>();

		private static float nextScan;

		private static Vector3 scanPosition;

		private static Player scanningPlayer;

		private static int queryDepth;

		private static int craftingDepth;

		private static List<Container> sources;

		internal static IEnumerable<Container> LoadedContainers => Containers.Where((Container c) => (Object)(object)c != (Object)null);

		internal static void Initialize(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Enabled = config.Bind<bool>("Crafting", "CraftFromChests", false, "Use materials from nearby accessible closed chests for crafting, upgrades and building. One toggle and range for all three. Furnace feeding is separate.");
			Radius = config.Bind<float>("Crafting", "ChestRange", 20f, new ConfigDescription("Maximum distance from the player in metres.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
		}

		private static bool Accessible(Container c, Player player)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c != (Object)null && c.m_inventory != null && (Object)(object)((Component)c).GetComponentInParent<TombStone>() == (Object)null && (Object)(object)c.m_nview != (Object)null && c.m_nview.IsValid() && c.m_nview.IsOwner() && !c.IsInUse() && c.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 0 && ((Object)(object)c.m_wagon == (Object)null || !c.m_wagon.InUse()) && Vector3.Distance(((Component)player).transform.position, ((Component)c).transform.position) <= Radius.Value && c.CheckAccess(player.GetPlayerID()))
			{
				if (c.m_checkGuardStone)
				{
					return PrivateArea.CheckAccess(((Component)c).transform.position, 0f, false, false);
				}
				return true;
			}
			return false;
		}

		internal static bool MachineAccess(Vector3 position, long creator)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				if (!((Object)(object)allArea == (Object)null) && allArea.IsEnabled() && allArea.IsInside(position, 0f))
				{
					if (allArea.m_piece.GetCreator() == creator || allArea.IsPermitted(creator))
					{
						return true;
					}
					flag = true;
				}
			}
			return !flag;
		}

		internal static List<Container> ForMachine(Vector3 center, long creator, float range = 10f)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			Containers.RemoveWhere((Container c) => (Object)(object)c == (Object)null);
			return (from c in Containers
				where MachineChestAccess.Allowed(c, center, creator, range)
				orderby Vector3.SqrMagnitude(((Component)c).transform.position - center)
				select c).ToList();
		}

		private static List<Container> Scan(Player player, bool force)
		{
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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)
			if (force || (Object)(object)player != (Object)(object)scanningPlayer || Time.time >= nextScan || Vector3.Distance(scanPosition, ((Component)player).transform.position) > 1f)
			{
				Containers.RemoveWhere((Container c) => (Object)(object)c == (Object)null);
				nearby = (from c in Containers
					where Accessible(c, player)
					orderby Vector3.SqrMagnitude(((Component)c).transform.position - ((Component)player).transform.position)
					select c).ToList();
				scanningPlayer = player;
				scanPosition = ((Component)player).transform.position;
				nextScan = Time.time + 0.5f;
			}
			return nearby.Where((Container c) => Accessible(c, player)).ToList();
		}

		private static bool Enter(Player player, bool force = false)
		{
			if (!Enabled.Value || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (queryDepth == 0 || force)
			{
				sources = Scan(player, force);
				if (force)
				{
					foreach (Container source in sources)
					{
						source.Load();
					}
				}
			}
			queryDepth++;
			return true;
		}

		private static void Exit(bool entered)
		{
			if (entered)
			{
				queryDepth--;
				if (queryDepth == 0)
				{
					sources = null;
				}
			}
		}

		private static bool Query(Inventory inventory)
		{
			if (queryDepth > 0 && sources != null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				return inventory == ((Humanoid)Player.m_localPlayer).GetInventory();
			}
			return false;
		}
	}
	internal static class DualUtility
	{
		private sealed class State
		{
			internal ItemData Extra;

			internal bool Swapping;
		}

		private sealed class Swap
		{
			internal Player Player;

			internal State State;

			internal ItemData Primary;
		}

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		private static class Equip
		{
			private static bool Prefix(Humanoid __instance, ItemData item, ref bool __result, out Swap __state)
			{
				__state = null;
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val == null || item == null || PlayerSlots.EquipmentIndex(item) != 4 || Get(val).Swapping)
				{
					return true;
				}
				State state = Get(val);
				if (((Humanoid)val).IsItemEquiped(item))
				{
					return true;
				}
				int num = PlayerSlots.Tag(item);
				bool flag = num == 11 || (num != 4 && ((Humanoid)val).m_utilityItem != null && state.Extra == null);
				ItemData val2 = (flag ? ((Humanoid)val).m_utilityItem : state.Extra);
				if (val2 != null && val2.m_shared.m_name == item.m_shared.m_name)
				{
					__result = false;
					return false;
				}
				if (flag)
				{
					__state = Begin(val);
				}
				return true;
			}

			private static void Postfix(Humanoid __instance, ItemData item, bool __result, Swap __state)
			{
				if (__result && __instance is Player && PlayerSlots.EquipmentIndex(item) == 4)
				{
					PlayerSlots.SetTag(item, (__state == null) ? 4 : 11);
				}
			}

			private static void Finalizer(Swap __state)
			{
				End(__state);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
		private static class Unequip
		{
			private static void Prefix(Humanoid __instance, ItemData item, out Swap __state)
			{
				__state = null;
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !Get(val).Swapping && item != null && Extra((Humanoid)(object)val) == item)
				{
					__state = Begin(val);
				}
			}

			private static void Finalizer(Swap __state)
			{
				End(__state);
			}
		}

		[HarmonyPatch(typeof(Humanoid), "IsItemEquiped")]
		private static class IsEquipped
		{
			private static void Postfix(Humanoid __instance, ItemData item, ref bool __result)
			{
				if (item != null && Extra(__instance) == item)
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UnequipAllItems")]
		private static class UnequipAll
		{
			private static void Prefix(Humanoid __instance)
			{
				ItemData val = Extra(__instance);
				if (val != null)
				{
					__instance.UnequipItem(val, false);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UnequipDeathDropItems")]
		private static class Death
		{
			private static void Prefix(Player __instance)
			{
				ItemData val = Extra((Humanoid)(object)__instance);
				if (val != null)
				{
					((Humanoid)__instance).UnequipItem(val, false);
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UpdateEquipmentStatusEffects")]
		private static class Effects
		{
			private static bool Prefix(Humanoid __instance)
			{
				if (!(__instance is Player))
				{
					return true;
				}
				ItemData[] obj = new ItemData[9]
				{
					__instance.m_leftItem,
					__instance.m_rightItem,
					__instance.m_chestItem,
					__instance.m_legItem,
					__instance.m_helmetItem,
					__instance.m_shoulderItem,
					__instance.m_utilityItem,
					__instance.m_trinketItem,
					Extra(__instance)
				};
				HashSet<StatusEffect> hashSet = new HashSet<StatusEffect>();
				ItemData[] array = (ItemData[])(object)obj;
				foreach (ItemData val in array)
				{
					if (val != null)
					{
						if ((Object)(object)val.m_shared.m_equipStatusEffect != (Object)null)
						{
							hashSet.Add(val.m_shared.m_equipStatusEffect);
						}
						if (__instance.HaveSetEffect(val))
						{
							hashSet.Add(val.m_shared.m_setStatusEffect);
						}
					}
				}
				foreach (StatusEffect equipmentStatusEffect in __instance.m_equipmentStatusEffects)
				{
					if (!hashSet.Contains(equipmentStatusEffect))
					{
						((Character)__instance).m_seman.RemoveStatusEffect(equipmentStatusEffect.NameHash(), false);
					}
				}
				foreach (StatusEffect item in hashSet)
				{
					if (!__instance.m_equipmentStatusEffects.Contains(item))
					{
						((Character)__instance).m_seman.AddStatusEffect(item, false, 0, 0f, (short)(-1));
					}
				}
				__instance.m_equipmentStatusEffects.Clear();
				__instance.m_equipmentStatusEffects.UnionWith(hashSet);
				return false;
			}
		}

		[HarmonyPatch(typeof(Humanoid), "GetSetCount")]
		private static class SetCount
		{
			private static void Postfix(Humanoid __instance, string setName, ref int __result)
			{
				if (Extra(__instance)?.m_shared.m_setName == setName)
				{
					__result++;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "UpdateEquipment")]
		private static class Durability
		{
			private static void Postfix(Humanoid __instance, float dt)
			{
				ItemData val = Extra(__instance);
				if (val != null && val.m_shared.m_useDurability)
				{
					__instance.DrainEquipedItemDurability(val, dt);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdateModifiers")]
		private static class Modifiers
		{
			private static void Postfix(Player __instance)
			{
				ItemData val = Extra((Humanoid)(object)__instance);
				if (val != null && Player.s_equipmentModifierSourceFields != null)
				{
					for (int i = 0; i < __instance.m_equipmentModifierValues.Length; i++)
					{
						__instance.m_equipmentModifierValues[i] += (float)Player.s_equipmentModifierSourceFields[i].GetValue(val.m_shared);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "GetEquipmentWeight")]
		private static class EquipmentWeight
		{
			private static void Postfix(Humanoid __instance, ref float __result)
			{
				__result += Extra(__instance)?.m_shared.m_weight ?? 0f;
			}
		}

		[HarmonyPatch(typeof(Player), "GetEquipmentEitrRegenModifier")]
		private static class Eitr
		{
			private static void Postfix(Player __instance, ref float __result)
			{
				__result += Extra((Humanoid)(object)__instance)?.m_shared.m_eitrRegenModifier ?? 0f;
			}
		}

		private static readonly ConditionalWeakTable<Player, State> States = new ConditionalWeakTable<Player, State>();

		private static State Get(Player player)
		{
			return States.GetValue(player, (Player _) => new State());
		}

		internal static ItemData Extra(Humanoid player)
		{
			Player val = (Player)(object)((player is Player) ? player : null);
			if (val == null)
			{
				return null;
			}
			return Get(val).Extra;
		}

		internal static void Validate(Player player)
		{
			ItemData val = Extra((Humanoid)(object)player);
			if (val != null && !((Humanoid)player).GetInventory().ContainsItem(val))
			{
				((Humanoid)player).UnequipItem(val, false);
			}
		}

		private static Swap Begin(Player player)
		{
			State state = Get(player);
			Swap swap = new Swap
			{
				Player = player,
				State = state,
				Primary = ((Humanoid)player).m_utilityItem
			};
			((Humanoid)player).m_utilityItem = state.Extra;
			state.Extra = swap.Primary;
			state.Swapping = true;
			return swap;
		}

		private static void End(Swap swap)
		{
			if (swap != null)
			{
				swap.State.Extra = ((Humanoid)swap.Player).m_utilityItem;
				((Humanoid)swap.Player).m_utilityItem = swap.Primary;
				swap.State.Swapping = false;
				((Humanoid)swap.Player).SetupEquipment();
			}
		}
	}
	internal static class FurnaceFeeding
	{
		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		private static class Feed
		{
			private static void Prefix(Smelter __instance)
			{
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				if (!Enabled.Value || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner() || (Object)(object)__instance.m_fuelItem == (Object)null || ((Object)((Component)__instance.m_fuelItem).gameObject).name != "Coal")
				{
					return;
				}
				Piece val = ((Component)__instance).GetComponent<Piece>() ?? ((Component)__instance).GetComponentInParent<Piece>();
				long num = (((Object)(object)val != (Object)null) ? val.GetCreator() : 0);
				if (num == 0L || !ChestCrafting.MachineAccess(((Component)__instance).transform.position, num))
				{
					return;
				}
				int num2 = FurnacePolicy.FuelSpace(__instance.GetFuel(), __instance.m_maxFuel);
				int num3 = Math.Max(0, __instance.m_maxOre - __instance.GetQueueSize());
				if (num2 == 0 && num3 == 0)
				{
					return;
				}
				foreach (Container item in ChestCrafting.ForMachine(((Component)__instance).transform.position, num))
				{
					Inventory inventory = item.GetInventory();
					bool flag = false;
					ItemData[] array = inventory.GetAllItems().ToArray();
					foreach (ItemData val2 in array)
					{
						string text = (((Object)(object)val2.m_dropPrefab != (Object)null) ? ((Object)val2.m_dropPrefab).name : "");
						int num4 = 0;
						if (text == "Coal" && num2 > 0)
						{
							num4 = Math.Min(val2.m_stack, num2);
							__instance.SetFuel(__instance.GetFuel() + (float)num4);
							num2 -= num4;
						}
						else if (num3 > 0 && FurnacePolicy.IsRawOre(text) && __instance.IsItemAllowed(text))
						{
							num4 = Math.Min(val2.m_stack, num3);
							for (int j = 0; j < num4; j++)
							{
								__instance.QueueOre(text, val2.m_cheated);
							}
							num3 -= num4;
						}
						if (num4 != 0)
						{
							val2.m_stack -= num4;
							flag = true;
						}
					}
					if (flag)
					{
						inventory.m_inventory.RemoveAll((ItemData item) => item.m_stack <= 0);
						inventory.Changed(false, false);
					}
					if (num2 == 0 && num3 == 0)
					{
						break;
					}
				}
			}
		}

		private static ConfigEntry<bool> Enabled;

		internal static void Initialize(ConfigFile config)
		{
			Enabled = config.Bind<bool>("Furnaces", "AutoFeedCoalAndOre", false, "Automatically supply coal and raw ore from accessible closed chests within a fixed 10 metres of the furnace. Only coal-fuelled furnaces and accepted raw ores; no wood, food or refined bars. Output collection has its own Production setting.");
		}
	}
	internal static class MachineChestAccess
	{
		internal static bool Allowed(Container chest, Vector3 center, long creator, float range)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)chest != (Object)null && chest.m_inventory != null && (Object)(object)((Component)chest).GetComponentInParent<TombStone>() == (Object)null && (Object)(object)chest.m_nview != (Object)null && chest.m_nview.IsValid() && chest.m_nview.IsOwner() && !chest.IsInUse() && chest.m_nview.GetZDO().GetInt(ZDOVars.s_inUse, 0) == 0 && ((Object)(object)chest.m_wagon == (Object)null || !chest.m_wagon.InUse()) && Vector3.Distance(center, ((Component)chest).transform.position) <= range && chest.CheckAccess(creator))
			{
				if (chest.m_checkGuardStone)
				{
					return ChestCrafting.MachineAccess(((Component)chest).transform.position, creator);
				}
				return true;
			}
			return false;
		}
	}
	internal static class PlayerSlots
	{
		internal sealed class State
		{
			internal Player Player;

			internal int NormalRows = 6;

			internal bool Loading;
		}

		[HarmonyPatch(typeof(Player), "Awake")]
		private static class AwakePatch
		{
			private static void Postfix(Player __instance)
			{
				Track(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "Load")]
		private static class LoadPatch
		{
			private static void Prefix(Player __instance)
			{
				Track(__instance).Loading = true;
			}

			private static void Postfix(Player __instance)
			{
				Track(__instance).Loading = false;
				Normalize(__instance);
			}

			private static void Finalizer(Player __instance)
			{
				Track(__instance).Loading = false;
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		private static class SavePatch
		{
			private static void Prefix(Player __instance)
			{
				Normalize(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "SetInventorySize")]
		private static class ResizePatch
		{
			private static bool Prefix(Player __instance, int rows)
			{
				__instance.AddUniqueKeyValue("invrows", Math.Max(0, Math.Min(9, rows)).ToString());
				Normalize(__instance);
				if ((Object)(object)InventoryGui.instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					InventoryGui.instance.SetInventorySize(Track(__instance).NormalRows);
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "FindEmptySlot")]
		private static class EmptyCellPatch
		{
			private static bool Prefix(Inventory __instance, bool topFirst, ref Vector2i __result)
			{
				//IL_0063: 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_003a: Unknown result type (might be due to invalid IL or missing references)
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				if (!TryState(__instance, out var state) || state.Loading)
				{
					return true;
				}
				for (int i = 0; i < state.NormalRows; i++)
				{
					int num = (topFirst ? i : (state.NormalRows - i - 1));
					for (int j = 0; j < __instance.GetWidth(); j++)
					{
						if (__instance.GetItemAt(j, num) == null)
						{
							__result = new Vector2i(j, num);
							return false;
						}
					}
				}
				__result = new Vector2i(-1, -1);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "GetEmptySlots")]
		private static class EmptyCountPatch
		{
			private static bool Prefix(Inventory __instance, ref int __result)
			{
				if (!TryState(__instance, out var state) || state.Loading)
				{
					return true;
				}
				__result = 0;
				for (int i = 0; i < state.NormalRows; i++)
				{
					for (int j = 0; j < __instance.GetWidth(); j++)
					{
						if (__instance.GetItemAt(j, i) == null)
						{
							__result++;
						}
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "HaveEmptySlot")]
		private static class HasSpacePatch
		{
			private static bool Prefix(Inventory __instance, ref bool __result)
			{
				if (!TryState(__instance, out var state) || state.Loading)
				{
					return true;
				}
				__result = __instance.GetEmptySlots() > 0;
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int)
		})]
		private static class CanAddPatch
		{
			private static bool Prefix(Inventory __instance, ItemData item, int stack, ref bool __result)
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_002e: 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)
				if (!TryState(__instance, out var state) || state.Loading)
				{
					return true;
				}
				int slot = Tag(item);
				Vector2i val = Position(state, slot);
				__result = (ValidSlot(item, slot) && __instance.GetItemAt(val.x, val.y) == null) || __instance.FindFreeStackSpace(item.m_shared.m_name, (float)item.m_worldLevel) + __instance.GetEmptySlots() * item.m_shared.m_maxStackSize >= ((stack <= 0) ? item.m_stack : stack);
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "StackAll")]
		private static class StackPatch
		{
			private static void Prefix(Inventory fromInventory, out bool __state)
			{
				__state = Plugin.ProtectSlots.Value && TryState(fromInventory, out var _);
				if (__state)
				{
					stackDepth++;
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					stackDepth--;
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })]
		private static class AddPatch
		{
			private static bool Prefix(Inventory __instance, ItemData item, ref bool __result)
			{
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: 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_0078: 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)
				if (stackDepth > 0 && Tag(item) >= 0)
				{
					__result = false;
					return false;
				}
				if (QuickStack.Transferring && QuickStack.Protected(item))
				{
					__result = false;
					return false;
				}
				if (!TryState(__instance, out var state) || state.Loading || __instance.ContainsItem(item))
				{
					return true;
				}
				int slot = Tag(item);
				if (!ValidSlot(item, slot))
				{
					return true;
				}
				Vector2i val = Position(state, slot);
				if (__instance.GetItemAt(val.x, val.y) != null)
				{
					return true;
				}
				item.m_gridPos = val;
				__instance.m_inventory.Add(item);
				__instance.Changed(true, item.m_cheated && !Achievements.IsCheatedAtAll());
				__result = true;
				return false;
			}
		}

		[HarmonyPatch(typeof(Inventory), "AddItem", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(int),
			typeof(int),
			typeof(bool)
		})]
		private static class CoordinatePatch
		{
			private static bool Prefix(Inventory __instance, ItemData item, int x, int y, ref bool __result)
			{
				if (!TryState(__instance, out var state) || state.Loading || y < state.NormalRows)
				{
					return true;
				}
				int slot = SlotAt(state, x, y);
				if (ValidSlot(item, slot))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		internal const string SlotKey = "GearAndStorage.slot";

		private static readonly ConditionalWeakTable<Inventory, State> States = new ConditionalWeakTable<Inventory, State>();

		private static int stackDepth;

		internal static bool TryState(Inventory inventory, out State state)
		{
			return States.TryGetValue(inventory, out state);
		}

		internal static State Track(Player player)
		{
			return States.GetValue(((Humanoid)player).GetInventory(), (Inventory _) => new State
			{
				Player = player,
				NormalRows = Plugin.Rows.Value
			});
		}

		internal static int EquipmentIndex(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			ItemType itemType = item.m_shared.m_itemType;
			if ((int)itemType <= 11)
			{
				if ((int)itemType == 6)
				{
					return 0;
				}
				if ((int)itemType == 7)
				{
					return 1;
				}
				if ((int)itemType == 11)
				{
					return 2;
				}
			}
			else
			{
				if ((int)itemType == 17)
				{
					return 3;
				}
				if ((int)itemType == 18)
				{
					return 4;
				}
				if ((int)itemType == 24)
				{
					return 12;
				}
			}
			return -1;
		}

		internal static int Tag(ItemData item)
		{
			if (item != null && item.m_customData.TryGetValue("GearAndStorage.slot", out var value) && int.TryParse(value, out var result))
			{
				return result;
			}
			return -1;
		}

		internal static void SetTag(ItemData item, int slot)
		{
			if (slot < 0)
			{
				item.m_customData.Remove("GearAndStorage.slot");
			}
			else
			{
				item.m_customData["GearAndStorage.slot"] = slot.ToString();
			}
		}

		internal static bool ValidSlot(ItemData item, int slot)
		{
			if (slot != 12)
			{
				if (slot != 11)
				{
					if (slot >= 0 && slot < 5 + Plugin.QuickCount.Value)
					{
						if (slot < 5)
						{
							return EquipmentIndex(item) == slot;
						}
						return true;
					}
					return false;
				}
				return EquipmentIndex(item) == 4;
			}
			return EquipmentIndex(item) == 12;
		}

		internal static Vector2i Position(State state, int slot)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2i((slot == 12) ? 6 : ((slot == 11) ? 5 : ((slot < 5) ? slot : (slot - 5))), state.NormalRows + ((!LayoutPlanner.IsEquipment(slot)) ? 1 : 0));
		}

		internal static int SlotAt(State state, int x, int y)
		{
			if (y == state.NormalRows && x >= 0 && x < 5)
			{
				return x;
			}
			if (y == state.NormalRows && x == 5)
			{
				return 11;
			}
			if (y == state.NormalRows && x == 6)
			{
				return 12;
			}
			if (y == state.NormalRows + 1 && x >= 0 && x < Plugin.QuickCount.Value)
			{
				return 5 + x;
			}
			return -1;
		}

		internal static ItemData GetSlot(Player player, int slot)
		{
			return ((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData x) => Tag(x) == slot));
		}

		internal static void Normalize(Player player)
		{
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			State state = Track(player);
			if (state.Loading || player.m_isLoading)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = Plugin.Rows.Value;
			string s = default(string);
			if (player.TryGetUniqueKeyValue("invrows", ref s) && int.TryParse(s, out var result))
			{
				num = Math.Max(num, Math.Min(9, result));
			}
			List<ItemData> allItems = inventory.GetAllItems();
			List<LayoutItem> list = new List<LayoutItem>(allItems.Count);
			for (int i = 0; i < allItems.Count; i++)
			{
				ItemData val = allItems[i];
				int slot = Tag(val);
				if (val.m_equipped && EquipmentIndex(val) >= 0)
				{
					slot = ((val == DualUtility.Extra((Humanoid)(object)player)) ? 11 : EquipmentIndex(val));
				}
				if (!ValidSlot(val, slot))
				{
					slot = -1;
				}
				list.Add(new LayoutItem
				{
					Id = i,
					X = val.m_gridPos.x,
					Y = val.m_gridPos.y,
					Slot = slot,
					Equipped = val.m_equipped
				});
			}
			LayoutResult layoutResult = LayoutPlanner.Arrange(list, inventory.GetWidth(), num, Plugin.QuickCount.Value);
			if (layoutResult.NormalRows > num && layoutResult.NormalRows != state.NormalRows)
			{
				Plugin.Log.LogWarning((object)("Inventory recovery: added visible space to preserve all items (" + layoutResult.NormalRows + " normal rows)."));
			}
			state.NormalRows = layoutResult.NormalRows;
			foreach (LayoutItem item in layoutResult.Items)
			{
				ItemData obj = allItems[item.Id];
				obj.m_gridPos = new Vector2i(item.X, item.Y);
				SetTag(obj, item.Slot);
			}
			inventory.m_height = state.NormalRows + 2;
		}
	}
	[BepInPlugin("mkova.GearAndStorage", "GearAndStorage", "0.5.7")]
	[BepInIncompatibility("randyknapp.mods.equipmentandquickslots")]
	[BepInIncompatibility("shudnal.ExtraSlots")]
	[BepInIncompatibility("Azumatt.AzuExtendedPlayerInventory")]
	[BepInIncompatibility("aedenthorn.ExtendedPlayerInventory")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "mkova.GearAndStorage";

		public const string Version = "0.5.7";

		internal static ModDataLayout Data;

		internal static ConfigEntry<int> Rows;

		internal static ConfigEntry<int> QuickCount;

		internal static ConfigEntry<bool> ProtectSlots;

		internal static ConfigEntry<bool> AnchorAboveGuardianPower;

		internal static ConfigEntry<Vector2> HudPosition;

		internal static ConfigEntry<Vector2> PanelPosition;

		internal static ConfigEntry<Vector2> GuardianPowerOffset;

		internal static readonly ConfigEntry<KeyboardShortcut>[] Keys = new ConfigEntry<KeyboardShortcut>[6];

		internal static ManualLogSource Log;

		private Harmony harmony;

		private bool active;

		internal static bool CanUseQuickSlots
		{
			get
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && !((Character)localPlayer).IsDead() && !localPlayer.m_isLoading && !QuestUi.Open)
				{
					return CanAct(localPlayer);
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Expected O, but got Unknown
			//IL_0124: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0345: Expected O, but got Unknown
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Data = new ModDataLayout(Paths.ConfigPath);
			Data.Ensure();
			if (!File.Exists(Data.SettingsPath) && File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				File.Copy(((BaseUnityPlugin)this).Config.ConfigFilePath, Data.SettingsPath);
			}
			ConfigFile value = new ConfigFile(Data.SettingsPath, false, ((BaseUnityPlugin)this).Info.Metadata);
			(AccessTools.Field(typeof(BaseUnityPlugin), "<Config>k__BackingField") ?? throw new MissingFieldException("BepInEx BaseUnityPlugin.Config backing field")).SetValue(this, value);
			Rows = ((BaseUnityPlugin)this).Config.Bind<int>("Player", "InventoryRows", 6, new ConfigDescription("Minimum normal inventory rows; purchased rows and recovery space are preserved.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(4, 9), Array.Empty<object>()));
			QuickCount = ((BaseUnityPlugin)this).Config.Bind<int>("QuickSlots", "Count", 3, new ConfigDescription("Quick slots. Removed slots return items to normal inventory.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), Array.Empty<object>()));
			HudPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("QuickSlots", "HudPosition", new Vector2(20f, 160f), "HUD position in pixels from the lower left corner.");
			AnchorAboveGuardianPower = ((BaseUnityPlugin)this).Config.Bind<bool>("QuickSlots", "AnchorAboveGuardianPower", true, "Center the quick bar above the guardian power (Eikthyr) icon. Disable to use HudPosition.");
			GuardianPowerOffset = ((BaseUnityPlugin)this).Config.Bind<Vector2>("QuickSlots", "GuardianPowerOffset", new Vector2(0f, 12f), "Offset in screen pixels from the top of the guardian power display: X horizontal, Y gap above it.");
			PanelPosition = ((BaseUnityPlugin)this).Config.Bind<Vector2>("Equipment", "PanelPosition", new Vector2(12f, -20f), "Slot panel offset from the upper right corner of the player inventory.");
			ProtectSlots = ((BaseUnityPlugin)this).Config.Bind<bool>("Protection", "ProtectFromStackAll", true, "Keep equipment and quick slot items out of bulk container stacking.");
			KeyCode[] array = new KeyCode[6];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			KeyCode[] array2 = (KeyCode[])(object)array;
			for (int i = 0; i < Keys.Length; i++)
			{
				Keys[i] = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("QuickSlots", "Hotkey" + (i + 1), (i < 3) ? new KeyboardShortcut(array2[i], (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }) : new KeyboardShortcut(array2[i], Array.Empty<KeyCode>()), "Use this quick slot once per key press, also while moving or sprinting. Letters follow the current keyboard layout; hold the specified modifiers (LeftAlt is the left Alt).");
			}
			Storage.Initialize(((BaseUnityPlugin)this).Config);
			WeightSettings.Initialize(((BaseUnityPlugin)this).Config);
			StackSettings.Initialize(((BaseUnityPlugin)this).Config);
			PortalRules.Initialize(((BaseUnityPlugin)this).Config);
			ChestCrafting.Initialize(((BaseUnityPlugin)this).Config);
			FurnaceFeeding.Initialize(((BaseUnityPlugin)this).Config);
			ProductionStorage.Initialize(((BaseUnityPlugin)this).Config);
			WorkbenchNetwork.Initialize(((BaseUnityPlugin)this).Config);
			QuickStack.Initialize(((BaseUnityPlugin)this).Config);
			QuestSystem.Initialize(((BaseUnityPlugin)this).Config);
			QuestUi.Initialize(((BaseUnityPlugin)this).Config);
			ServerSettings.Initialize(((BaseUnityPlugin)this).Config);
			if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.valheim_plus", out var value2))
			{
				BaseUnityPlugin instance = value2.Instance;
				ConfigEntry<bool> val = default(ConfigEntry<bool>);
				if ((Object)(object)instance == (Object)null || !instance.Config.TryGetEntry<bool>(new ConfigDefinition("Inventory", "enabled"), ref val) || val.Value)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"GearAndStorage not started: disable Valheim Plus [Inventory] first. Other V+ features may remain enabled.");
					return;
				}
			}
			harmony = new Harmony("mkova.GearAndStorage");
			harmony.PatchAll(typeof(Plugin).Assembly);
			active = true;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"GearAndStorage 0.5.7 loaded: independent storage, equipment and quick slots.");
		}

		private void LateUpdate()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			if (!active)
			{
				return;
			}
			ServerSettings.Tick();
			StackSettings.Tick();
			WorkbenchNetwork.Tick();
			QuestNetwork.Tick();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || localPlayer.m_isLoading)
			{
				QuickStack.Tick(localPlayer, canAct: false);
				QuestUi.Close();
				return;
			}
			QuestSystem.Tick(localPlayer);
			DualUtility.Validate(localPlayer);
			if ((Object)(object)InventoryGui.instance == (Object)null || InventoryGui.instance.m_dragItem == null)
			{
				PlayerSlots.Normalize(localPlayer);
			}
			bool flag = CanAct(localPlayer);
			QuestUi.Tick(flag);
			QuickStack.Tick(localPlayer, flag && !QuestUi.Open);
			if (!flag || QuestUi.Open)
			{
				return;
			}
			KeyboardShortcut value = QuickStack.Key.Value;
			if (((KeyboardShortcut)(ref value)).IsDown())
			{
				QuickStack.Start(localPlayer);
				return;
			}
			for (int i = 0; i < QuickCount.Value; i++)
			{
				if (QuickSlotInput.IsDown(Keys[i].Value))
				{
					ItemData slot = PlayerSlots.GetSlot(localPlayer, 5 + i);
					if (slot != null)
					{
						((Humanoid)localPlayer).UseItem(((Humanoid)localPlayer).GetInventory(), slot, false);
					}
				}
			}
		}

		private static bool CanAct(Player player)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			if (Application.isFocused)
			{
				if (!InventoryGui.IsVisible() && !Menu.IsVisible() && !Console.IsVisible() && !TextInput.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !((Character)player).IsTeleporting() && !((Character)player).InCutscene() && !Hud.InRadial())
				{
					if ((Object)(object)Minimap.instance != (Object)null)
					{
						return (int)Minimap.instance.m_mode != 2;
					}
					return true;
				}
				return false;
			}
			return false;
		}

		private void OnGUI()
		{
			if (active)
			{
				if (!QuestUi.Open)
				{
					SlotUi.DrawHud();
				}
				QuestUi.Draw();
			}
		}

		private void OnDestroy()
		{
			ServerSettings.Restore();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	internal static class PortalRules
	{
		private sealed class Rule
		{
			internal string Biome;

			internal ConfigEntry<bool> Manual;

			internal ConfigEntry<string> Items;

			internal ConfigEntry<string> Trophy;

			internal string WorldKey => "gearandstorage_portals_" + Biome.ToLowerInvariant();
		}

		[HarmonyPatch(typeof(ItemStand), "SetVisualItem")]
		private static class Altar
		{
			private static void Postfix(ItemStand __instance)
			{
				if (!AutoUnlock.Value || (Object)(object)ZoneSystem.instance == (Object)null || (Object)(object)__instance.m_guardianPower == (Object)null || !__instance.HaveAttachment() || (Object)(object)ObjectDB.instance == (Object)null)
				{
					return;
				}
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(__instance.GetAttachedItem());
				if ((Object)(object)itemPrefab == (Object)null)
				{
					return;
				}
				foreach (Rule rule in Rules)
				{
					if (!string.IsNullOrWhiteSpace(rule.Trophy.Value) && Contains(rule.Trophy.Value, ((Object)itemPrefab).name) && !ZoneSystem.instance.GetGlobalKey(rule.WorldKey))
					{
						ZoneSystem.instance.SetGlobalKey(rule.WorldKey);
						Plugin.Log.LogInfo((object)("Portal transport unlocked for this world: " + rule.Biome + " (trophy at altar)."));
					}
				}
			}
		}

		[HarmonyPatch(typeof(Inventory), "IsTeleportable")]
		private static class Teleport
		{
			private static void Postfix(Inventory __instance, ref bool __result)
			{
				if (__result)
				{
					return;
				}
				foreach (ItemData allItem in __instance.GetAllItems())
				{
					if (allItem.m_shared.m_toolTier >= 1000)
					{
						return;
					}
					if (allItem.m_shared.m_teleportable)
					{
						continue;
					}
					GameObject dropPrefab = allItem.m_dropPrefab;
					if ((Object)(object)dropPrefab == (Object)null)
					{
						return;
					}
					bool flag = false;
					foreach (Rule rule in Rules)
					{
						if (Contains(rule.Items.Value, ((Object)dropPrefab).name) && (rule.Manual.Value || (AutoUnlock.Value && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(rule.WorldKey))))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						return;
					}
				}
				__result = true;
			}
		}

		private static readonly List<Rule> Rules = new List<Rule>();

		private static ConfigEntry<bool> AutoUnlock;

		internal static void Initialize(ConfigFile config)
		{
			AutoUnlock = config.Bind<bool>("Portals", "UnlockOnTrophyAtAltar", true, "Permanently unlock the biome for this world when its boss trophy is mounted at the sacrificial stones. Boss kills and decorative item stands do not count.");
			Add(config, "Meadows", "TrophyEikthyr", "");
			Add(config, "BlackForest", "TrophyTheElder", "CopperOre,TinOre,Copper,Tin,Bronze");
			Add(config, "Swamp", "TrophyBonemass", "IronScrap,Iron");
			Add(config, "Mountain", "TrophyDragonQueen", "SilverOre,Silver,DragonEgg");
			Add(config, "Plains", "TrophyGoblinKing", "BlackMetalScrap,BlackMetal");
			Add(config, "Mistlands", "TrophySeekerQueen", "DvergrNeedle,CopperScrap");
			Add(config, "AshLands", "TrophyFader", "FlametalOreNew,FlametalNew,FlametalOre,Flametal");
			Add(config, "DeepNorth", "", "Gold");
			Add(config, "Ocean", "", "");
		}

		private static void Add(ConfigFile config, string biome, string trophy, string items)
		{
			Rules.Add(new Rule
			{
				Biome = biome,
				Manual = config.Bind<bool>("Portals", "Allow" + biome, false, "Additionally allow restricted items of " + biome + " even before the trophy unlock. False does not revoke an altar unlock."),
				Items = config.Bind<string>("Portals.Items", biome, items, "Comma-separated item prefab names assigned to this biome. Unknown items remain blocked; extend for modded items."),
				Trophy = config.Bind<string>("Portals.Trophies", biome, trophy, "Boss trophy prefab mounted on a guardian-power altar. Empty means no automatic trophy unlock for this biome.")
			});
		}

		private static bool Contains(string csv, string value)
		{
			string[] array = csv.Split(',');
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), value, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ProductionOptions
	{
		internal static readonly Dictionary<string, ConfigEntry<bool>> Stations = new Dictionary<string, ConfigEntry<bool>>(StringComparer.Ordinal);

		internal static readonly Dictionary<string, string> Keys = new Dictionary<string, string>(StringComparer.Ordinal)
		{
			["smelter"] = "Smelter",
			["blastfurnace"] = "BlastFurnace",
			["charcoal_kiln"] = "CharcoalKiln",
			["windmill"] = "Windmill",
			["spinningwheel"] = "SpinningWheel",
			["eitrrefinery"] = "EitrRefinery",
			["piece_cookingstation"] = "CookingStation",
			["piece_cookingstation_iron"] = "IronCookingStation",
			["piece_oven"] = "Oven",
			["fermenter"] = "Fermenter",
			["sapcollector"] = "SapCollector"
		};

		internal static void Initialize(ConfigFile config)
		{
			ConfigEntry<bool> val = config.Bind<bool>("Production", "StoreOutputInChests", false, (ConfigDescription)null);
			bool value = val.Value;
			foreach (string value2 in Keys.Values)
			{
				Stations[value2] = config.Bind<bool>("Production", value2, value, "Automatically store finished output from this station in accessible closed chests. Server controlled.");
			}
			config.Remove(((ConfigEntryBase)val).Definition);
		}

		internal static bool Allows(string prefab)
		{
			if (prefab == null)
			{
				return false;
			}
			if (prefab.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				prefab = prefab.Substring(0, prefab.Length - "(Clone)".Length);
			}
			if (Keys.TryGetValue(prefab, out var value) && Stations.TryGetValue(value, out var value2))
			{
				return value2.Value;
			}
			return false;
		}
	}
	internal static class ProductionStorage
	{
		private sealed class OutputBatch
		{
			internal Component Machine;

			internal OutputBatch Parent;

			internal readonly HashSet<ItemDrop> Drops = new HashSet<ItemDrop>();

			internal HashSet<string> Prefabs;
		}

		[HarmonyPatch]
		private static class CaptureOutput
		{
			private static IEnumerable<MethodBase> TargetMethods()
			{
				yield return typeof(Smelter).GetMethod("Spawn", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				yield return typeof(Fermenter).GetMethod("DelayedTap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				yield return typeof(CookingStation).GetMethod("SpawnItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				yield return typeof(SapCollector).GetMethod("RPC_Extract", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}

			private static void Prefix(Component __instance, out OutputBatch __state)
			{
				__state = new OutputBatch
				{
					Machine = __instance,
					Parent = current,
					Prefabs = (CanRun(__instance, out var _) ? OutputNames(__instance) : new HashSet<string>())
				};
				current = __state;
			}

			[HarmonyPriority(0)]
			private static void Postfix(OutputBatch __state)
			{
				ProductionStorage.current = __state.Parent;
				foreach (ItemDrop drop in __state.Drops)
				{
					Store(__state.Machine, drop);
				}
			}

			private static void Finalizer(OutputBatch __state)
			{
				if (__state != null)
				{
					current = __state.Parent;
				}
			}
		}

		[HarmonyPatch(typeof(ItemDrop), "Awake")]
		private static class CaptureItem
		{
			private static void Postfix(ItemDrop __instance)
			{
				if (current != null && (Object)(object)__instance.m_itemData?.m_dropPrefab != (Object)null && current.Prefabs.Contains(((Object)__instance.m_itemData.m_dropPrefab).name))
				{
					current.Drops.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Smelter), "UpdateSmelter")]
		private static class FlushSmelter
		{
			private static void Postfix(Smelter __instance)
			{
				if (!CanRun((Component)(object)__instance, out var _))
				{
					return;
				}
				int processedQueueSize = __instance.GetProcessedQueueSize();
				if (processedQueueSize > 0)
				{
					ItemConversion itemConversion = __instance.GetItemConversion(__instance.m_nview.GetZDO().GetString(ZDOVars.s_spawnOre, ""));
					if (itemConversion != null && CanStoreAll((Component)(object)__instance, itemConversion.m_to, processedQueueSize))
					{
						__instance.SpawnProcessed();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Fermenter), "SlowUpdate")]
		private static class CollectFermenter
		{
			private static void Postfix(Fermenter __instance)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Invalid comparison between Unknown and I4
				if (CanRun((Component)(object)__instance, out var _) && (int)__instance.GetStatus() == 3)
				{
					ItemConversion itemConversion = __instance.GetItemConversion(__instance.GetContent());
					if ((Object)(object)itemConversion?.m_to != (Object)null && CanStoreAll((Component)(object)__instance, itemConversion.m_to, (long)itemConversion.m_producedItems * (long)itemConversion.m_to.m_itemData.m_stack))
					{
						__instance.RPC_Tap(0L);
					}
				}
			}
		}

		[HarmonyPatch(typeof(SapCollector), "UpdateTick")]
		private static class CollectSap
		{
			private static void Postfix(SapCollector __instance)
			{
				if (CanRun((Component)(object)__instance, out var _) && !((Object)(object)Game.instance == (Object)null) && !((Object)(object)__instance.m_spawnItem == (Object)null))
				{
					int num = Game.instance.ScaleDrops(__instance.m_spawnItem.m_itemData, 1);
					if (CanStoreAll((Component)(object)__instance, __instance.m_spawnItem, (long)__instance.GetLevel() * (long)num, newWorldLevel: false))
					{
						__instance.RPC_Extract(0L);
					}
				}
			}
		}

		[HarmonyPatch(typeof(CookingStation), "UpdateCooking")]
		private static class CollectCooking
		{
			private static void Postfix(CookingStation __instance)
			{
				//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
				if (!CanRun((Component)(object)__instance, out var _) || (Object)(object)Game.instance == (Object)null || Game.instance.GetPlayerProfile() == null || __instance.m_recordCrafter)
				{
					return;
				}
				string text = default(string);
				float num = default(float);
				Status val = default(Status);
				bool flag = default(bool);
				for (int i = 0; i < __instance.m_slots.Length; i++)
				{
					__instance.GetSlot(i, ref text, ref num, ref val, ref flag);
					if (!(text == "") && __instance.IsItemDone(text))
					{
						ObjectDB instance = ObjectDB.instance;
						object obj;
						if (instance == null)
						{
							obj = null;
						}
						else
						{
							GameObject itemPrefab = instance.GetItemPrefab(text);
							obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
						}
						ItemDrop val2 = (ItemDrop)obj;
						if (!CanStoreAll((Component)(object)__instance, val2, ((Object)(object)val2 != (Object)null) ? val2.m_itemData.m_stack : 0))
						{
							break;
						}
						__instance.RPC_RemoveDoneItem(0L, ((Component)__instance).transform.position + ((Component)__instance).transform.forward, 1);
					}
				}
			}
		}

		internal static ConfigEntry<float> Range;

		[ThreadStatic]
		private static OutputBatch current;

		internal static void Initialize(ConfigFile config)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			ProductionOptions.Initialize(config);
			Range = config.Bind<float>("Production", "ChestRange", 10f, new ConfigDescription("Maximum distance from the producing machine to a chest in metres. Server controlled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 100f), Array.Empty<object>()));
		}

		internal static bool CanRun(Component machine, out long creator)
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			creator = 0L;
			if ((Object)(object)machine == (Object)null || !ProductionOptions.Allows(((Object)machine.gameObject).name))
			{
				return false;
			}
			ZNetView component = machine.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner())
			{
				return false;
			}
			Piece val = machine.GetComponent<Piece>() ?? machine.GetComponentInParent<Piece>();
			creator = (((Object)(object)val != (Object)null) ? val.GetCreator() : 0);
			if (creator != 0L)
			{
				return ChestCrafting.MachineAccess(machine.transform.position, creator);
			}
			return false;
		}

		internal static bool CanStoreAll(Component machine, ItemDrop prefab, long amount, bool newWorldLevel = true)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)prefab == (Object)null || amount <= 0 || !CanRun(machine, out var creator))
			{
				return false;
			}
			ItemData val = prefab.m_itemData.Clone();
			StackSettings.Apply(val);
			if (newWorldLevel)
			{
				val.m_worldLevel = (byte)Game.m_worldLevel;
			}
			foreach (Container item in ChestCrafting.ForMachine(machine.transform.position, creator, Range.Value))
			{
				item.Load();
				amount -= ProductionTransfer.Capacity(item.GetInventory(), val);
				if (amount <= 0)
				{
					return true;
				}
			}
			return false;
		}

		internal static void Store(Component machine, ItemDrop drop)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)drop == (Object)null || drop.m_itemData == null || drop.m_itemData.m_stack <= 0 || (Object)(object)drop.m_nview == (Object)null || !drop.m_nview.IsValid() || !drop.m_nview.IsOwner() || (Object)(object)ZNetScene.instance == (Object)null || !CanRun(machine, out var creator))
			{
				return;
			}
			int stack = drop.m_itemData.m_stack;
			try
			{
				StackSettings.Apply(drop.m_itemData);
				foreach (Container item in ChestCrafting.ForMachine(machine.transform.position, creator, Range.Value))
				{
					item.Load();
					if (ProductionTransfer.Deposit(item.GetInventory(), drop.m_itemData) > 0)
					{
						item.Save();
					}
					if (drop.m_itemData.m_stack == 0)
					{
						break;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Production storage: output kept at machine: " + ex.Message));
			}
			finally
			{
				if (drop.m_itemData.m_stack != stack)
				{
					try
					{
						drop.Save();
						if (drop.m_itemData.m_stack == 0)
						{
							ZNetScene.instance.Destroy(((Component)drop).gameObject);
						}
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogError((object)("Production storage: cannot save/remove output remainder: " + ex2.Message));
					}
				}
			}
		}

		private static HashSet<string> OutputNames(Component machine)
		{
			Smelter val = (Smelter)(object)((machine is Smelter) ? machine : null);
			IEnumerable<ItemDrop> source;
			if (val != null)
			{
				source = val.m_conversion.Select((ItemConversion c) => c.m_to);
			}
			else
			{
				Fermenter val2 = (Fermenter)(object)((machine is Fermenter) ? machine : null);
				if (val2 != null)
				{
					source = val2.m_conversion.Select((ItemConversion c) => c.m_to);
				}
				else
				{
					CookingStation val3 = (CookingStation)(object)((machine is CookingStation) ? machine : null);
					if (val3 != null)
					{
						source = val3.m_conversion.Select((ItemConversion c) => c.m_to).Concat((IEnumerable<ItemDrop>)(object)new ItemDrop[1] { val3.m_overCookedItem });
					}
					else
					{
						SapCollector val4 = (SapCollector)(object)((machine is SapCollector) ? machine : null);
						source = (IEnumerable<ItemDrop>)((val4 == null) ? ((Array)Array.Empty<ItemDrop>()) : ((Array)new ItemDrop[1] { val4.m_spawnItem }));
					}
				}
			}
			return new HashSet<string>(from i in source
				where (Object)(object)i != (Object)null
				select ((Object)((Component)i).gameObject).name, StringComparer.Ordinal);
		}
	}
	internal static class ProductionTransfer
	{
		internal static long Capacity(Inventory inventory, ItemData item)
		{
			if (item?.m_shared == null || item.m_shared.m_maxStackSize < 1)
			{
				return 0L;
			}
			long num = (long)Math.Max(0, inventory.GetEmptySlots()) * (long)item.m_shared.m_maxStackSize;
			if (item.m_shared.m_maxStackSize > 1)
			{
				foreach (ItemData allItem in inventory.GetAllItems())
				{
					if (allItem.m_shared.m_name == item.m_shared.m_name && allItem.m_quality == item.m_quality && allItem.m_worldLevel == item.m_worldLevel)
					{
						num += Math.Max(0, allItem.m_shared.m_maxStackSize - allItem.m_stack);
					}
				}
			}
			return num;
		}

		internal static int Deposit(Inventory inventory, ItemData source)
		{
			int stack = source.m_stack;
			while (source.m_stack > 0)
			{
				int num = (int)Math.Min(Math.Min((long)source.m_stack, (long)source.m_shared.m_maxStackSize), Capacity(inventory, source));
				if (num <= 0)
				{
					break;
				}
				ItemData val = source.Clone();
				val.m_stack = num;
				long num2 = Count(inventory);
				bool flag = false;
				try
				{
					inventory.AddItem(val);
				}
				catch (Exception ex)
				{
					flag = true;
					Plugin.Log.LogWarning((object)("Production storage: inventory callback failed: " + ex.Message));
				}
				int num3 = (int)Math.Max(0L, Math.Min(num, Count(inventory) - num2));
				source.m_stack -= num3;
				if (flag || num3 < num)
				{
					break;
				}
			}
			return stack - source.m_stack;
		}

		private static long Count(Inventory inventory)
		{
			return ((IEnumerable<ItemData>)inventory.GetAllItems()).Sum((Func<ItemData, long>)((ItemData item) => item.m_stack));
		}
	}
	[HarmonyPatch]
	internal static class QuestCameraInput
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return typeof(GameCamera).GetMethod("UpdateCamera", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			yield return typeof(GameCamera).GetMethod("UpdateFreeFly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		}

		internal static float ReadScroll()
		{
			if (!QuestUi.Open)
			{
				return ZInput.GetMouseScrollWheel();
			}
			return 0f;
		}

		internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo original = typeof(ZInput).GetMethod("GetMouseScrollWheel", BindingFlags.Static | BindingFlags.Public);
			MethodInfo replacement = typeof(QuestCameraInput).GetMethod("ReadScroll", BindingFlags.Static | BindingFlags.NonPublic);
			bool found = false;
			foreach (CodeInstruction instruction in instructions)
			{
				if (instruction.opcode == OpCodes.Call && object.Equals(instruction.operand, original))
				{
					instruction.opcode = OpCodes.Call;
					instruction.operand = replacement;
					found = true;
				}
				yield return instruction;
			}
			if (!found)
			{
				throw new InvalidOperationException("GearAndStorage: camera scroll call not found in this game version.");
			}
		}
	}
	internal static class QuestFiles
	{
		internal static readonly JsonSerializerSettings Json = new JsonSerializerSettings
		{
			TypeNameHandling = (TypeNameHandling)0,
			MaxDepth = 32
		};

		internal static QuestList Parse(string json)
		{
			QuestList questList = JsonConvert.DeserializeObject<QuestList>(json, Json);
			if (questList?.Quests == null || questList.Quests.Count > 10000)
			{
				throw new InvalidDataException("Invalid quest list");
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (QuestDefinition quest in questList.Quests)
			{
				if (quest == null || string.IsNullOrWhiteSpace(quest.ID) || !hashSet.Add(quest.ID))
				{
					throw new InvalidDataException("Missing/duplicate quest ID");
				}
				QuestDefinition questDefinition = quest;
				if (questDefinition.KillReqs == null)
				{
					questDefinition.KillReqs = new List<QuestObjective>();
				}
				questDefinition = quest;
				if (questDefinition.GatherReqs == null)
				{
					questDefinition.GatherReqs = new List<QuestObjective>();
				}
				questDefinition = quest;
				if (questDefinition.RewardItems == null)
				{
					questDefinition.RewardItems = new List<QuestReward>();
				}
				questDefinition = quest;
				if (questDefinition.SkillRewards == null)
				{
					questDefinition.SkillRewards = new List<QuestSkill>();
				}
				if (quest.KillReqs.Count + quest.GatherReqs.Count + quest.RewardItems.Count + quest.SkillRewards.Count > 100)
				{
					throw new InvalidDataException("Too many objectives/rewards: " + quest.ID);
				}
				foreach (QuestObjective item in quest.KillReqs.Concat(quest.GatherReqs))
				{
					if (item == null || string.IsNullOrWhiteSpace(item.Prefab) || item.Amount <= 0 || item.Amount > 1000000)
					{
						throw new InvalidDataException("Invalid objective: " + quest.ID);
					}
				}
				if (quest.KillReqs.Select((QuestObjective o) => o.Prefab).Distinct<string>(StringComparer.OrdinalIgnoreCase).Count() != quest.KillReqs.Count || quest.GatherReqs.Select((QuestObjective o) => o.Prefab).Distinct<string>(StringComparer.OrdinalIgnoreCase).Count() != quest.GatherReqs.Count)
				{
					throw new InvalidDataException("Duplicate objective: " + quest.ID);
				}
				foreach (QuestReward rewardItem in quest.RewardItems)
				{
					if (rewardItem == null || string.IsNullOrWhiteSpace(rewardItem.Prefab) || rewardItem.Amount <= 0 || rewardItem.Amount > 100000)
					{
						throw new InvalidDataException("Invalid reward: " + quest.ID);
					}
				}
				foreach (QuestSkill skillReward in quest.SkillRewards)
				{
					if (skillReward == null || string.IsNullOrWhiteSpace(skillReward.Skill) || float.IsNaN(skillReward.Amount) || float.IsInfinity(skillReward.Amount) || skillReward.Amount <= 0f)
					{
						throw new InvalidDataException("Invalid skill reward: " + quest.ID);
					}
				}
				quest.Title = (string.IsNullOrWhiteSpace(quest.Title) ? quest.ID : quest.Title);
			}
			return questList;
		}

		internal static QuestList Load(string folder, Action<string> warn)
		{
			QuestList questList = new QuestList();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (!Directory.Exists(folder))
			{
				return questList;
			}
			foreach (string item in Directory.GetFiles(folder, "quest*.json").OrderBy<string, string>((string f) => f, StringComparer.Ordinal))
			{
				try
				{
					foreach (QuestDefinition quest in Parse(File.ReadAllText(item)).Quests)
					{
						if (!hashSet.Add(quest.ID))
						{
							warn("Duplicate quest ID ignored: " + quest.ID + " in " + Path.GetFileName(item));
							continue;
						}
						quest.SourceFile = Path.GetFileNameWithoutExtension(item);
						questList.Quests.Add(quest);
					}
				}
				catch (Exception ex)
				{
					warn(Path.GetFileName(item) + ": " + ex.Message);
				}
			}
			return questList;
		}
	}
	internal static class QuestNetwork
	{
		[HarmonyPatch(typeof(Character), "OnDeath")]
		private static class Death
		{
			private static void Prefix(Character __instance)
			{
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009c: Expected O, but got Unknown
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				if (!QuestSystem.Enabled.Value || __instance is Player || (Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
				{
					return;
				}
				HitData lastHit = __instance.m_lastHit;
				Character obj = ((lastHit != null) ? lastHit.GetAttacker() : null);
				Player val = (Player)(object)((obj is Player) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				ZDO zDO = __instance.m_nview.GetZDO();
				string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
				if (ServerSettings.IsServer)
				{
					Relay(zDO.m_uid, ((Character)val).GetZDOID(), prefabName, ZNet.GetUID());
					return;
				}
				ZPackage val2 = new ZPackage();
				val2.Write(zDO.m_uid);
				val2.Write(((Character)val).GetZDOID());
				val2.Write(prefabName);
				ZRpc serverRPC = ZNet.instance.GetServerRPC();
				if (serverRPC != null)
				{
					serverRPC.Invoke("GearAndStorage.QuestKill", new object[1] { val2 });
				}
			}
		}

		private const string Catalog = "GearAndStorage.Quests";

		private const string Kill = "GearAndStorage.QuestKill";

		private const string Credit = "GearAndStorage.QuestCredit";

		private static string stamp;

		private static string catalog = "{\"Quests\":[]}";

		private static float nextScan;

		private static readonly HashSet<ZDOID> kills = new HashSet<ZDOID>();

		internal static void Reset()
		{
			stamp = null;
			nextScan = 0f;
			catalog = "{\"Quests\":[]}";
			kills.Clear();
			QuestSystem.Reset();
		}

		internal static void Tick()
		{
			if (!ServerSettings.IsServer || Time.realtimeSinceStartup < nextScan)
			{
				return;
			}
			nextScan = Time.realtimeSinceStartup + 5f;
			try
			{
				string text = (Directory.Exists(QuestSystem.Folder) ? string.Join("|", from f in Directory.GetFiles(QuestSystem.Folder, "quest*.json").OrderBy<string, string>((string f) => f, StringComparer.Ordinal)
					select f + File.GetLastWriteTimeUtc(f).Ticks + new FileInfo(f).Length) : "missing");
				if (text == stamp)
				{
					return;
				}
				stamp = text;
				QuestList questList = QuestFiles.Load(QuestSystem.Folder, delegate(string s)
				{
					Plugin.Log.LogWarning((object)s);
				});
				catalog = JsonConvert.SerializeObject((object)questList, QuestFiles.Json);
				QuestSystem.SetDefinitions(questList);
				Plugin.Log.LogInfo((object)("Loaded " + questList.Quests.Count + " GearAndStorage quests from " + QuestSystem.Folder));
				foreach (ZNetPeer item in ServerSettings.Clients())
				{
					item.m_rpc.Invoke("GearAndStorage.Quests", new object[1] { catalog });
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Quest catalog: " + ex.Message));
			}
		}

		internal static void Send(ZRpc rpc)
		{
			nextScan = 0f;
			Tick();
			rpc.Invoke("GearAndStorage.Quests", new object[1] { catalog });
		}

		internal static void Register(ZRpc rpc)
		{
			rpc.Register<string>("GearAndStorage.Quests", (Action<ZRpc, string>)delegate(ZRpc sender, string json)
			{
				if (!ServerSettings.FromServer(sender))
				{
					return;
				}
				try
				{
					if (json.Length > 4000000)
					{
						throw new InvalidDataException("Quest catalog too large");
					}
					QuestSystem.SetDefinitions(QuestFiles.Parse(json));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Server quest catalog rejected: " + ex.Message));
				}
			});
			rpc.Register<ZPackage>("GearAndStorage.QuestKill", (Action<ZRpc, ZPackage>)delegate(ZRpc sender, ZPackage pkg)
			{
				//IL_0022: 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)
				if (ServerSettings.IsServer)
				{
					ZNetPeer peer = ZNet.instance.GetPeer(sender);
					if (peer != null && peer.IsReady())
					{
						try
						{
							Relay(pkg.ReadZDOID(), pkg.ReadZDOID(), pkg.ReadString(), peer.m_uid);
						}
						catch (Exception ex)
						{
							Plugin.Log.LogWarning((object)("Quest kill packet: " + ex.Message));
						}
					}
				}
			});
			rpc.Register<string>("GearAndStorage.QuestCredit", (Action<ZRpc, string>)delegate(ZRpc sender, string prefab)
			{
				if (ServerSettings.FromServer(sender))
				{
					QuestSystem.Credit(prefab, 1, kill: true);
				}
			});
		}

		private static void Relay(ZDOID victim, ZDOID attacker, string prefab, long owner)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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)
			if (!QuestSystem.Enabled.Value || kills.Contains(victim))
			{
				return;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(victim);
			if (zDO == null || zDO.GetOwner() != owner || zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode(prefab))
			{
				return;
			}
			kills.Add(victim);
			if ((Object)(object)Player.m_localPlayer != (Object)null && ((Character)Player.m_localPlayer).GetZDOID() == attacker)
			{
				QuestSystem.Credit(prefab, 1, kill: true);
				return;
			}
			ZNetPeer? obj = ServerSettings.Clients().FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.m_characterID == attacker));
			if (obj != null)
			{
				obj.m_rpc.Invoke("GearAndStorage.QuestCredit", new object[1] { prefab });
			}
		}
	}
	internal static class QuestSystem
	{
		[HarmonyPatch]
		private static class Gather
		{
			private sealed class Scope
			{
				internal Dictionary<string, int> Before;
			}

			private static IEnumerable<MethodBase> TargetMethods()
			{
				return from m in typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
					where m.Name == "AddItem"
					select m;
			}

			private static void Prefix(Inventory __instance, out Scope __state)
			{
				__state = null;
				if (Enabled.Value && Book?.Active != null && !((Object)(object)loadedPlayer == (Object)null) && !loadedPlayer.m_isLoading && __instance == ((Humanoid)loadedPlayer).GetInventory())
				{
					__state = new Scope();
					if (gatherDepth++ == 0)
					{
						__state.Before = Counts(__instance);
					}
				}
			}

			private static void Finalizer(Inventory __instance, Scope __state)
			{
				if (__state == null)
				{
					return;
				}
				gatherDepth--;
				if (__state.Before == null)
				{
					return;
				}
				foreach (KeyValuePair<string, int> item in Counts(__instance))
				{
					__state.Before.TryGetValue(item.Key, out var value);
					if (item.Value > value)
					{
						Credit(item.Key, item.Value - value, kill: false);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "OnSpawned")]
		private static class Spawn
		{
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && Enabled.Value)
				{
					Load(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		private static class Persist
		{
			private static void Prefix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)loadedPlayer)
				{
					Save();
				}
			}
		}

		private const string ProgressKey = "GearAndStorage.questProgress";

		internal static ConfigEntry<bool> Enabled;

		internal static QuestBook Book;

		internal static string Notice = "";

		internal static QuestList Definitions = new QuestList();

		private static Player loadedPlayer;

		private static float rewardCheck;

		private static int gatherDepth;

		internal static string Folder => Plugin.Data.Quests;

		internal static void Initialize(ConfigFile config)
		{
			Enabled = config.Bind<bool>("Quests", "Enabled", true, "Read quest JSON files from GearAndStorage/Quests. One accepted quest, cumulative gather objectives and automatic rewards.");
		}

		internal static void SetDefinitions(QuestList list)
		{
			Definitions = list;
			if (Book != null)
			{
				Book = new QuestBook(list.Quests, Book.Progress);
			}
		}

		internal static void Reset()
		{
			Book = null;
			loadedPlayer = null;
			Definitions = new QuestList();
			Notice = "";
			QuestUi.Close();
		}

		private static void Load(Player player)
		{
			if ((Object)(object)loadedPlayer == (Object)(object)player)
			{
				return;
			}
			loadedPlayer = player;
			Notice = "";
			try
			{
				QuestProgress questProgress = null;
				if (player.m_customData.TryGetValue("GearAndStorage.questProgress", out var value))
				{
					questProgress = JsonConvert.DeserializeObject<QuestProgress>(value, QuestFiles.Json);
				}
				else
				{
					string text = player.GetPlayerName();
					char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
					foreach (char oldChar in invalidFileNameChars)
					{
						text = text.Replace(oldChar, '_');
					}
					string path = Path.Combine(Plugin.Data.Progress, "progress_" + text + ".json");
					if (File.Exists(path))
					{
						questProgress = JsonConvert.DeserializeObject<QuestProgress>(File.ReadAllText(path), QuestFiles.Json);
						Plugin.Log.LogInfo((object)("Imported quest progress for " + player.GetPlayerName() + " from GearAndStorage/Progress."));
					}
				}
				if (questProgress != null && questProgress.AcceptedQuestIDs?.Count > 1)
				{
					Notice = "Převzat jeden aktivní quest; ostatní lze přijmout později.";
				}
				Book = new QuestBook(Definitions.Quests, questProgress);
				Save();
			}
			catch (Exception ex)
			{
				Book = null;
				Notice = "Postup questů nelze načíst. Podrobnosti jsou v logu.";
				Plugin.Log.LogError((object)("Quest progress not modified: " + ex.Message));
			}
		}

		internal static void Save()
		{
			if ((Object)(object)loadedPlayer != (Object)null && Book != null)
			{
				loadedPlayer.m_customData["GearAndStorage.questProgress"] = JsonConvert.SerializeObject((object)Book.Progress, QuestFiles.Json);
			}
		}

		internal static void Credit(string prefab, int amount, bool kill)
		{
			if (Enabled.Value && Book != null && Book.Credit(prefab, amount, kill))
			{
				Save();
			}
		}

		internal static void Accept(QuestDefinition q)
		{
			if (Book == null || !Enabled.Value)
			{
				return;
			}
			string text = RewardProblem(q);
			if (text == null)
			{
				foreach (QuestObjective gatherReq in q.GatherReqs)
				{
					if ((Object)(object)ObjectDB.instance.GetItemPrefab(gatherReq.Prefab) == (Object)null)
					{
						text = "Chybí předmět úkolu: " + gatherReq.Prefab;
						break;
					}
				}
			}
			if (text == null)
			{
				foreach (QuestObjective killReq in q.KillReqs)
				{
					ZNetScene instance = ZNetScene.instance;
					object obj;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						GameObject prefab = instance.GetPrefab(killReq.Prefab);
						obj = ((prefab != null) ? prefab.GetComponent<Character>() : null);
					}
					if ((Object)obj == (Object)null)
					{
						text = "Chybí tvor úkolu: " + killReq.Prefab;
						break;
					}
				}
			}
			if (text != null)
			{
				Notice = text;
			}
			else if (Book.Accept(q.ID))
			{
				Notice = "Přijato: " + q.Title;
				Save();
			}
		}

		internal static void Abandon()
		{
			if (Book != null)
			{
				Book.Abandon();
				Notice = "Quest zrušen.";
				Save();
			}
		}

		internal static void Tick(Player player)
		{
			if (!Enabled.Value || (Object)(object)player == (Object)null || player.m_isLoading || ((Character)player).IsDead())
			{
				return;
			}
			Load(player);
			if (Book != null && Book.Ready && !(Time.realtimeSinceStartup < rewardCheck))
			{
				rewardCheck = Time.realtimeSinceStartup + 1f;
				if (!((Object)(object)InventoryGui.instance != (Object)null) || InventoryGui.instance.m_dragItem == null)
				{
					Reward();
				}
			}
		}

		internal static string RewardProblem(QuestDefinition q)
		{
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ObjectDB.instance == (Object)null)
			{
				return "Předměty ještě nejsou načtené.";
			}
			foreach (QuestReward rewardItem in q.RewardItems)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(rewardItem.Prefab);
				if ((Object)(object)((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null) == (Object)null)
				{
					return "Chybí předmět odměny: " + rewardItem.Prefab;
				}
			}
			foreach (QuestSkill skillReward in q.SkillRewards)
			{
				if (!Enum.TryParse<SkillType>(skillReward.Skill, ignoreCase: true, out SkillType result) || !Enum.IsDefined(typeof(SkillType), result) || (int)result == 0)
				{
					return "Neznámá dovednost: " + skillReward.Skill;
				}
			}
			return null;
		}

		private static void Reward()
		{
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			QuestDefinition active = Book.Active;
			string text = RewardProblem(active);
			if (text != null)
			{
				Notice = text;
				return;
			}
			Inventory inventory = ((Humanoid)loadedPlayer).GetInventory();
			List<Vector2i> list = new List<Vector2i>();
			PlayerSlots.State state = PlayerSlots.Track(loadedPlayer);
			for (int i = 0; i < state.NormalRows; i++)
			{
				for (int j = 0; j < inventory.GetWidth(); j++)
				{
					if (inventory.GetItemAt(j, i) == null)
					{
						list.Add(new Vector2i(j, i));
					}
				}
			}
			List<ItemData> list2 = new List<ItemData>();
			foreach (QuestReward rewardItem in active.RewardItems)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(rewardItem.Prefab);
				ItemData itemData = itemPrefab.GetComponent<ItemDrop>().m_itemData;
				int num = rewardItem.Amount;
				while (num > 0)
				{
					ItemData val = itemData.Clone();
					val.m_dropPrefab = itemPrefab;
					val.m_stack = Math.Min(num, Math.Max(1, val.m_shared.m_maxStackSize));
					val.m_worldLevel = Game.m_worldLevel;
					val.m_durability = val.GetMaxDurability();
					num -= val.m_stack;
					list2.Add(val);
					if (list2.Count > list.Count)
					{
						Notice = "Splněno — uvolni místo v běžném inventáři pro odměnu.";
						return;
					}
				}
			}
			for (int k = 0; k < list2.Count; k++)
			{
				list2[k].m_gridPos = list[k];
				inventory.m_inventory.Add(list2[k]);
			}
			Book.Complete();
			Save();
			inventory.Changed(false, false);
			foreach (QuestSkill skillReward in active.SkillRewards)
			{
				try
				{
					((Character)loadedPlayer).RaiseSkill((SkillType)Enum.Parse(typeof(SkillType), skillReward.Skill, ignoreCase: true), skillReward.Amount);
				}
				catch (Exception ex)
				{
					Plugin.Log.LogError((object)("Quest skill reward failed: " + ex.Message));
				}
			}
			Notice = "Splněno: " + active.Title;
			((Character)loadedPlayer).Message((MessageType)2, Notice + " — odměna přidána.", 0, (Sprite)null, false);
		}

		private static Dictionary<string, int> Counts(Inventory inventory)
		{
			return (from i in inventory.GetAllItems()
				where (Object)(object)i.m_dropPrefab != (Object)null
				select i).GroupBy<ItemData, string>((ItemData i) => ((Object)i.m_dropPrefab).name, StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, ItemData>, string, int>((IGrouping<string, ItemData> g) => g.Key, (IGrouping<string, ItemData> g) => g.Sum((ItemData i) => i.m_stack), StringComparer.OrdinalIgnoreCase);
		}
	}
	internal static class QuestUi
	{
		[HarmonyPatch(typeof(Player), "TakeInput")]
		private static class BlockInput
		{
			private static void Postfix(ref bool __result)
			{
				if (Open)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		private static class BlockController
		{
			private static void Postfix(ref bool __result)
			{
				if (Open)
				{
					__result = false;
				}
			}
		}

		[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
		private static class Mouse
		{
			private static bool Prefix()
			{
				if (!Open)
				{
					return true;
				}
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
				return false;
			}
		}

		[HarmonyPatch(typeof(Menu), "Update")]
		private static class Escape
		{
			private static bool Prefix()
			{
				return !Open;
			}
		}

		internal static bool Open;

		private static ConfigEntry<KeyboardShortcut> key;

		private static ConfigEntry<Vector2> offset;

		private static ConfigEntry<float> width;

		private static Vector2 scroll;

		private static Vector2 hudScroll;

		private static Vector2 completedScroll;

		private static string search = "";

		private static int page;

		private static bool editingSearch;

		private static List<QuestDefinition> navigationSource;

		private static List<QuestLine> lines = new List<QuestLine>();

		private static string selectedLine;

		private static GUIStyle body;

		private static GUIStyle title;

		private static GUIStyle small;

		private static GUIStyle button;

		private static GUIStyle panel;

		internal static void Initialize(ConfigFile config)
		{
			//IL_0012: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			key = config.Bind<KeyboardShortcut>("Controls", "QuestJournal", new KeyboardShortcut((KeyCode)108, Array.Empty<KeyCode>()), "Open the quest journal.");
			offset = config.Bind<Vector2>("QuestsUI", "Offset", Vector2.zero, "Quest tracker offset from its position to the left of the minimap: X right, Y down, in screen pixels.");
			width = config.Bind<float>("QuestsUI", "Width", 280f, new ConfigDescription("Compact quest tracker width in pixels. Height follows its content.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(220f, 600f), Array.Empty<object>()));
		}

		internal static void Close()
		{
			if (Open)
			{
				Open = false;
				if ((Object)(object)GameCamera.instance != (Object)null)
				{
					GameCamera.instance.UpdateMouseCapture();
				}
			}
		}

		internal static void Tick(bool canOpen)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			if (!QuestSystem.Enabled.Value)
			{
				Close();
				return;
			}
			KeyboardShortcut value;
			if (Open)
			{
				if (Input.GetKeyDown((KeyCode)27))
				{
					goto IL_003d;
				}
				if (!editingSearch)
				{
					value = key.Value;
					if (((KeyboardShortcut)(ref value)).IsDown())
					{
						goto IL_003d;
					}
				}
			}
			if (canOpen)
			{
				value = key.Value;
				if (((KeyboardShortcut)(ref value)).IsDown() && !Open)
				{
					Open = true;
					scroll = Vector2.zero;
					editingSearch = false;
					FocusActive();
				}
			}
			if (Open)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
			}
			return;
			IL_003d:
			Close();
		}

		private static void Styles()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_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)
			//IL_003c: Expected O, but got Unknown
			//IL_0041: Expected O, but got Unknown
			//IL_005a: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			//IL_010c: Expected O, but got Unknown
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_0133: Expected O, but got Unknown
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			if (body == null)
			{
				body = new GUIStyle(GUI.skin.label)
				{
					fontSize = 15,
					wordWrap = true,
					richText = false,
					padding = new RectOffset(4, 4, 3, 3)
				};
				body.normal.textColor = new Color(0.91f, 0.93f, 0.95f);
				title = new GUIStyle(body)
				{
					fontSize = 19,
					fontStyle = (FontStyle)1
				};
				title.normal.textColor = new Color(1f, 0.78f, 0.36f);
				small = new GUIStyle(body)
				{
					fontSize = 13
				};
				small.normal.textColor = new Color(0.71f, 0.77f, 0.81f);
				button = new GUIStyle(GUI.skin.button)
				{
					fontSize = 15,
					padding = new RectOffset(10, 10, 8, 8)
				};
				panel = new GUIStyle(GUI.skin.box)
				{
					padding = new RectOffset(14, 14, 12, 12)
				};
				Texture2D val = new Texture2D(1, 1);
				val.SetPixel(0, 0, new Color(0.045f, 0.055f, 0.07f, 0.93f));
				val.Apply();
				panel.normal.background = val;
			}
		}

		internal static string ItemName(string prefab)
		{
			ObjectDB instance = ObjectDB.instance;
			object obj = ((instance != null) ? instance.GetItemPrefab(prefab) : null);
			if (obj == null)
			{
				ZNetScene instance2 = ZNetScene.instance;
				obj = ((instance2 != null) ? instance2.GetPrefab(prefab) : null);
			}
			GameObject val = (GameObject)obj;
			string text = ((val == null) ? null : val.GetComponent<ItemDrop>()?.m_itemData.m_shared.m_name) ?? ((val == null) ? null : val.GetComponent<Character>()?.m_name) ?? prefab;
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}

		private static string Objectives(QuestDefinition q, bool progress)
		{
			StringBuilder stringBuilder = new StringBuilder();
			bool[] array = new bool[2] { true, false };
			foreach (bool flag in array)
			{
				foreach (QuestObjective item in flag ? q.KillReqs : q.GatherReqs)
				{
					int value = (progress ? QuestSystem.Book.Count(q, item, flag) : 0);
					stringBuilder.Append(flag ? "Zabít: " : "Získat: ").Append(ItemName(item.Prefab)).Append("  ");
					if (progress)
					{
						stringBuilder.Append(value).Append(" / ");
					}
					stringBuilder.Append(item.Amount).AppendLine();
				}
			}
			return stringBuilder.ToString().TrimEnd();
		}

		private static string Rewards(QuestDefinition q)
		{
			StringBuilder stringBuilder = new StringBuilder("Odměna: ");
			stringBuilder.Append(string.Join(", ", q.RewardItems.Select((QuestReward r) => r.Amount + "× " + ItemName(r.Prefab)).Concat(q.SkillRewards.Select((QuestSkill s) => s.Skill + " +" + s.Amount + " XP"))));
			if (q.RewardItems.Count == 0 && q.SkillRewards.Count == 0)
			{
				stringBuilder.Append("žádná");
			}
			return stringBuilder.ToString();
		}

		internal static void Draw()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			if (!QuestSystem.Enabled.Value || (Object)(object)Player.m_localPlayer == (Object)null || ((Character)Player.m_localPlayer).IsDead() || (Object)(object)Hud.instance == (Object)null)
			{
				return;
			}
			Styles();
			if (Open)
			{
				Journal();
			}
			else if (!InventoryGui.IsVisible() && !Menu.IsVisible() && !((Object)(object)Minimap.instance == (Object)null) && Minimap.instance.m_smallRoot.activeInHierarchy)
			{
				Rect val = SlotUi.ScreenRect((RectTransform)Minimap.instance.m_smallRoot.transform);
				float num = Math.Min(width.Value, Screen.width - 16);
				float num2 = Mathf.Clamp(((Rect)(ref val)).xMin - num - 12f + offset.Value.x, 8f, (float)Screen.width - num - 8f);
				float num3 = Mathf.Clamp((float)Screen.height - ((Rect)(ref val)).yMax + offset.Value.y, 8f, (float)(Screen.height - 100));
				List<(string, GUIStyle)> list = new List<(string, GUIStyle)> { ("AKTIVNÍ QUEST", small) };
				QuestDefinition questDefinition = QuestSystem.Book?.Active;
				if (questDefinition == null)
				{
					list.Add(("Žádný aktivní quest. Deník: " + ((object)key.Value/*cast due to .constrained prefix*/).ToString(), body));
				}
				else
				{
					list.Add((questDefinition.Title, title));
					list.Add((Objectives(questDefinition, progress: true), body));
					list.Add((Rewards(questDefinition), small));
				}
				if (!string.IsNullOrEmpty(QuestSystem.Notice) && QuestSystem.Notice != "Přijato: " + questDefinition?.Title)
				{
					list.Add((QuestSystem.Notice, small));
				}
				float innerWidth = num - (float)panel.padding.horizontal - 16f;
				float[] array = list.Select<(string, GUIStyle), float>(((string Text, GUIStyle Style) c) => c.Style.CalcHeight(new GUIContent(c.Text), innerWidth)).ToArray();
				float num4 = array.Sum() + (float)(3 * (list.Count - 1));
				float num5 = Mathf.Min(num4 + (float)panel.padding.vertical, (float)Screen.height - num3 - 8f);
				GUI.Box(new Rect(num2, num3, num, num5), GUIContent.none, panel);
				hudScroll = GUI.BeginScrollView(new Rect(num2 + (float)panel.padding.left, num3 + (float)panel.padding.top, num - (float)panel.padding.horizontal, num5 - (float)panel.padding.vertical), hudScroll, new Rect(0f, 0f, innerWidth, num4));
				float num6 = 0f;
				for (int num7 = 0; num7 < list.Count; num7++)
				{
					GUI.Label(new Rect(0f, num6, innerWidth, array[num7]), list[num7].Item1, list[num7].Item2);
					num6 += array[num7] + 3f;
				}
				GUI.EndScrollView();
			}
		}

		private static void UpdateNavigation()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			List<QuestDefinition> list = QuestSystem.Book?.Definitions;
			if (list != navigationSource)
			{
				navigationSource = list;
				lines = ((list == null) ? new List<QuestLine>() : QuestNavigation.ForJournal(list));
				if (!lines.Any((QuestLine l) => l.ID == selectedLine))
				{
					selectedLine = lines.FirstOrDefault()?.ID;
				}
				page = 0;
				scroll = (completedScroll = Vector2.zero);
			}
		}

		private static void SelectLine(QuestLine line)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			selectedLine = line.ID;
			page = 0;
			search = "";
			scroll = (completedScroll = Vector2.zero);
		}

		private static void FocusActive()
		{
			UpdateNavigation();
			QuestDefinition active = QuestSystem.Book?.Active;
			if (active != null)
			{
				QuestLine questLine = lines.FirstOrDefault((QuestLine l) => l.Quests.Contains(active));
				if (questLine != null)
				{
					SelectLine(questLine);
					page = new QuestLineProgress(questLine, QuestSystem.Book.Progress).PageOf(active);
				}
			}
		}

		private static