Decompiled source of ValheimStorage v1.3.2

ValheimStorage.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ValheimStorage")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a19f4b302348e8eadfcc58f94a7bd40d40e21ab3")]
[assembly: AssemblyProduct("ValheimStorage")]
[assembly: AssemblyTitle("ValheimStorage")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimStorage
{
	public static class CraftFromContainers
	{
		internal static bool CraftingAllowed(Player player)
		{
			if (!Plugin.ModActive() || !Plugin.enableCrafting.Value)
			{
				return false;
			}
			CraftingStation currentCraftingStation = player.GetCurrentCraftingStation();
			return (Object)(object)currentCraftingStation == (Object)null || Plugin.StationAllowed(((Component)currentCraftingStation).gameObject);
		}

		internal static bool BuildingAllowed(Piece piece)
		{
			return Plugin.ModActive() && Plugin.enableBuilding.Value && ((Object)(object)piece.m_craftingStation == (Object)null || Plugin.StationAllowed(((Component)piece.m_craftingStation).gameObject));
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
	public static class Player_HaveRequirementItems_Containers
	{
		private static void Postfix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount, ref bool __result)
		{
			if (__result || discover || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !CraftFromContainers.CraftingAllowed(__instance))
			{
				return;
			}
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if ((Object)(object)val.m_resItem == (Object)null)
				{
					continue;
				}
				string name = val.m_resItem.m_itemData.m_shared.m_name;
				int num = val.GetAmount(qualityLevel) * amount;
				int num2 = 0;
				for (int j = 1; j < val.m_resItem.m_itemData.m_shared.m_maxQuality + 1; j++)
				{
					int num3 = ((Humanoid)__instance).m_inventory.CountItems(name, j, true) + NearbyContainers.CountItems(__instance, name, j);
					if (num3 > num2)
					{
						num2 = num3;
					}
				}
				if (piece.m_requireOnlyOneIngredient)
				{
					if (num2 >= num)
					{
						__result = true;
						return;
					}
				}
				else if (num2 < num)
				{
					return;
				}
			}
			__result = !piece.m_requireOnlyOneIngredient;
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	public static class Player_HaveRequirementsPiece_Containers
	{
		private static void Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (__result || (int)mode == 1 || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !CraftFromContainers.BuildingAllowed(piece))
			{
				return;
			}
			if ((Object)(object)piece.m_craftingStation != (Object)null)
			{
				if ((int)mode == 2)
				{
					if (!__instance.m_knownStations.ContainsKey(piece.m_craftingStation.m_name))
					{
						return;
					}
				}
				else if ((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position) == (Object)null && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)22))
				{
					return;
				}
			}
			if (piece.m_dlc.Length > 0 && !DLCMan.instance.IsDLCInstalled(piece.m_dlc))
			{
				return;
			}
			Requirement[] resources = piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					int num = ((Humanoid)__instance).m_inventory.CountItems(name, -1, true) + NearbyContainers.CountItems(__instance, name);
					if (num < val.m_amount)
					{
						return;
					}
				}
			}
			__result = true;
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	public static class Player_ConsumeResources_Containers
	{
		private static bool Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Plugin.ModActive())
			{
				return true;
			}
			bool flag = ((Character)__instance).InPlaceMode();
			if (flag ? (!Plugin.enableBuilding.Value) : (!CraftFromContainers.CraftingAllowed(__instance)))
			{
				return true;
			}
			string context = (flag ? "building" : "crafting");
			foreach (Requirement val in requirements)
			{
				if ((Object)(object)val.m_resItem == (Object)null)
				{
					continue;
				}
				int num = val.GetAmount(qualityLevel) * multiplier;
				if (num > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					int num2 = Math.Min(((Humanoid)__instance).m_inventory.CountItems(name, itemQuality, true), num);
					if (num2 > 0)
					{
						((Humanoid)__instance).m_inventory.RemoveItem(name, num2, itemQuality, true);
					}
					if (num - num2 > 0)
					{
						NearbyContainers.RemoveItems(__instance, name, num - num2, itemQuality, context, ((Object)((Component)val.m_resItem).gameObject).name);
					}
				}
			}
			FlyingItems.Flush();
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	public static class InventoryGui_SetupRequirement_Containers
	{
		private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			if (!__result || (Object)(object)req?.m_resItem == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !CraftFromContainers.CraftingAllowed(player))
			{
				return;
			}
			int num = req.GetAmount(quality) * craftMultiplier;
			if (num > 0)
			{
				string name = req.m_resItem.m_itemData.m_shared.m_name;
				int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
				int num3 = NearbyContainers.CountItems(player, name);
				TMP_Text component = ((Component)elementRoot.Find("res_amount")).GetComponent<TMP_Text>();
				if (Plugin.showAvailable.Value && num3 > 0)
				{
					component.text = $"{num} ({num2 + num3})";
				}
				if (num2 < num && num2 + num3 >= num)
				{
					((Graphic)component).color = ((Mathf.Sin(Time.time * 10f) > 0f) ? Plugin.flashColor.Value : Color.white);
				}
			}
		}
	}
	public static class FavoriteItems
	{
		private const string customDataKey = "vs_favorite";

		private const string markerName = "VS_Favorite";

		private static bool spriteLoadAttempted;

		private static Sprite? favoriteSprite;

		internal static bool IsFavorite(ItemData? item)
		{
			return item?.m_customData.ContainsKey("vs_favorite") ?? false;
		}

		internal static void Toggle(ItemData item)
		{
			if (!item.m_customData.Remove("vs_favorite"))
			{
				item.m_customData["vs_favorite"] = "1";
			}
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, (IsFavorite(item) ? "Favorited " : "Unfavorited ") + item.m_shared.m_name, 0, (Sprite)null);
			}
		}

		internal static bool FavoriteKeyHeld()
		{
			//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_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = Plugin.favoriteModifier.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKey(((KeyboardShortcut)(ref value)).MainKey, true))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, true))
				{
					return false;
				}
			}
			return true;
		}

		internal static void UpdateMarkers(InventoryGrid grid)
		{
			if ((Object)(object)MarkerSprite() == (Object)null || grid.m_inventory == null)
			{
				return;
			}
			foreach (Element element in grid.m_elements)
			{
				Transform val = element.m_go.transform.Find("VS_Favorite");
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
			int width = grid.m_inventory.GetWidth();
			foreach (ItemData allItem in grid.m_inventory.GetAllItems())
			{
				if (IsFavorite(allItem))
				{
					GetMarker(grid.GetElement(allItem.m_gridPos.x, allItem.m_gridPos.y, width)).SetActive(true);
				}
			}
		}

		private static GameObject GetMarker(Element element)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0081: 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)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			Transform val = element.m_go.transform.Find("VS_Favorite");
			if ((Object)(object)val != (Object)null)
			{
				return ((Component)val).gameObject;
			}
			GameObject val2 = new GameObject("VS_Favorite", new Type[1] { typeof(RectTransform) });
			val2.transform.SetParent(element.m_go.transform, false);
			val2.transform.SetAsLastSibling();
			RectTransform val3 = (RectTransform)val2.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			val3.offsetMin = Vector2.zero;
			val3.offsetMax = Vector2.zero;
			Image val4 = val2.AddComponent<Image>();
			val4.sprite = MarkerSprite();
			((Graphic)val4).raycastTarget = false;
			return val2;
		}

		private static Sprite? MarkerSprite()
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if (spriteLoadAttempted)
			{
				return favoriteSprite;
			}
			spriteLoadAttempted = true;
			AssetBundle val = null;
			using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ValheimStorage.assets.vs"))
			{
				if (stream != null)
				{
					using MemoryStream memoryStream = new MemoryStream();
					stream.CopyTo(memoryStream);
					val = AssetBundle.LoadFromMemory(memoryStream.ToArray());
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)"[ValheimStorage] asset bundle 'vs' not found in mod DLL, favorite markers are invisible");
				return null;
			}
			favoriteSprite = val.LoadAsset<Sprite>("VS_FavBackground");
			if ((Object)(object)favoriteSprite == (Object)null)
			{
				Texture2D val2 = val.LoadAsset<Texture2D>("VS_FavBackground");
				if ((Object)(object)val2 != (Object)null)
				{
					favoriteSprite = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f));
				}
			}
			if ((Object)(object)favoriteSprite == (Object)null)
			{
				Debug.LogWarning((object)"[ValheimStorage] VS_FavBackground missing from asset bundle, favorite markers are invisible");
			}
			return favoriteSprite;
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "OnSelectedItem")]
	public static class InventoryGui_OnSelectedItem_ToggleFavorite
	{
		private static bool Prefix(InventoryGui __instance, ItemData? item)
		{
			if (item == null || (Object)(object)__instance.m_dragGo != (Object)null || !FavoriteItems.FavoriteKeyHeld())
			{
				return true;
			}
			FavoriteItems.Toggle(item);
			return false;
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	public static class InventoryGrid_UpdateGui_FavoriteMarkers
	{
		private static void Postfix(InventoryGrid __instance)
		{
			FavoriteItems.UpdateMarkers(__instance);
		}
	}
	[HarmonyPatch(typeof(Inventory), "StackAll")]
	public static class Inventory_StackAll_SkipFavorites
	{
		private static void Prefix(Inventory fromInventory, out List<ItemData> __state)
		{
			__state = fromInventory.m_inventory.FindAll((ItemData item) => FavoriteItems.IsFavorite(item));
			foreach (ItemData item in __state)
			{
				fromInventory.m_inventory.Remove(item);
			}
		}

		private static void Postfix(Inventory fromInventory, List<ItemData> __state)
		{
			if (__state.Count > 0)
			{
				fromInventory.m_inventory.AddRange(__state);
				fromInventory.Changed();
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "DropItem")]
	public static class Humanoid_DropItem_BlockFavorites
	{
		private static bool Prefix(Humanoid __instance, ItemData item, ref bool __result)
		{
			if (!FavoriteItems.IsFavorite(item))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "Unmark the favorite first to drop it", 0, (Sprite)null);
			__result = false;
			return false;
		}
	}
	public static class FlyingItems
	{
		private const string rpcName = "VS_QuickStackFly";

		private const int maxFlyersPerRun = 20;

		private const float flyerSize = 0.3f;

		private const float legSeconds = 0.7f;

		private const float staggerSeconds = 0.06f;

		private const float cullDistance = 200f;

		private static ZRoutedRpc? registeredOn;

		public static Func<Player, Vector3, List<Vector3>?>? routeResolver;

		private static readonly List<(string prefabName, Vector3[] path)> pending = new List<(string, Vector3[])>();

		internal static void RegisterRpc()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != registeredOn)
			{
				instance.Register<ZPackage>("VS_QuickStackFly", (Action<long, ZPackage>)RPC_Fly);
				registeredOn = instance;
			}
		}

		internal static void Queue(ItemData item, Player player, Vector3 containerPos)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				Add(((Object)item.m_dropPrefab).name, BuildPath(player, containerPos, toChest: true));
			}
		}

		internal static void QueueFromContainer(string prefabName, Player player, Vector3 containerPos)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Add(prefabName, BuildPath(player, containerPos, toChest: false));
		}

		private static Vector3[] BuildPath(Player player, Vector3 containerPos, bool toChest)
		{
			//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_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_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3> { containerPos + Vector3.up * 0.6f };
			List<Vector3> list2 = routeResolver?.Invoke(player, containerPos);
			if (list2 != null)
			{
				list.AddRange(list2);
			}
			list.Add(((Character)player).GetCenterPoint());
			if (toChest)
			{
				list.Reverse();
			}
			return list.ToArray();
		}

		private static void Add(string prefabName, Vector3[] path)
		{
			if (pending.Count < 20 && path.Length >= 2)
			{
				pending.Add((prefabName, path));
			}
		}

		internal static void Flush()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (pending.Count == 0)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(pending.Count);
			foreach (var (text, array) in pending)
			{
				val.Write(text);
				val.Write(array.Length);
				Vector3[] array2 = array;
				foreach (Vector3 val2 in array2)
				{
					val.Write(val2);
				}
			}
			pending.Clear();
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "VS_QuickStackFly", new object[1] { val });
			}
			else
			{
				val.SetPos(0);
				RPC_Fly(0L, val);
			}
		}

		private static void RPC_Fly(long sender, ZPackage package)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			int num = package.ReadInt();
			for (int i = 0; i < num; i++)
			{
				string text = package.ReadString();
				int num2 = package.ReadInt();
				Vector3[] array = (Vector3[])(object)new Vector3[num2];
				for (int j = 0; j < num2; j++)
				{
					array[j] = package.ReadVector3();
				}
				if ((Object)(object)localPlayer == (Object)null || array.Length < 2)
				{
					continue;
				}
				bool flag = false;
				Vector3[] array2 = array;
				foreach (Vector3 val in array2)
				{
					if (Vector3.Distance(val, ((Component)localPlayer).transform.position) <= 200f)
					{
						flag = true;
						break;
					}
				}
				GameObject val2 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(text) : null);
				if (flag && (Object)(object)val2 != (Object)null)
				{
					SpawnVisual(val2, array, i);
				}
			}
		}

		private static void SpawnVisual(GameObject itemPrefab, Vector3[] path, int index)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			MeshFilter componentInChildren = itemPrefab.GetComponentInChildren<MeshFilter>(true);
			MeshRenderer val = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).GetComponent<MeshRenderer>() : null);
			if (!((Object)(object)componentInChildren == (Object)null) && !((Object)(object)componentInChildren.sharedMesh == (Object)null) && !((Object)(object)val == (Object)null))
			{
				GameObject val2 = new GameObject("VS_FlyingItem");
				val2.AddComponent<MeshFilter>().sharedMesh = componentInChildren.sharedMesh;
				MeshRenderer val3 = val2.AddComponent<MeshRenderer>();
				((Renderer)val3).sharedMaterials = ((Renderer)val).sharedMaterials;
				((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val3).receiveShadows = false;
				Bounds bounds = componentInChildren.sharedMesh.bounds;
				float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
				val2.transform.localScale = Vector3.one * ((num > 0.001f) ? (0.3f / num) : 1f);
				FlyingItemVisual flyingItemVisual = val2.AddComponent<FlyingItemVisual>();
				flyingItemVisual.path = path;
				flyingItemVisual.legDuration = 0.7f;
				flyingItemVisual.delay = (float)index * 0.06f;
				val2.transform.position = path[0];
			}
		}
	}
	public class FlyingItemVisual : MonoBehaviour
	{
		public Vector3[] path = Array.Empty<Vector3>();

		public float legDuration = 0.7f;

		public float delay;

		private float progress;

		private void Update()
		{
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			Renderer component = ((Component)this).GetComponent<Renderer>();
			if (delay > 0f)
			{
				delay -= Time.deltaTime;
				component.enabled = false;
				return;
			}
			int num = path.Length - 1;
			if (num < 1)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			component.enabled = true;
			progress += Time.deltaTime / legDuration;
			if (progress >= (float)num)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			int num2 = Mathf.Min((int)progress, num - 1);
			float num3 = progress - (float)num2;
			Vector3 position = Vector3.Lerp(path[num2], path[num2 + 1], num3);
			position.y += Mathf.Sin(num3 * (float)Math.PI) * 1.2f;
			((Component)this).transform.position = position;
			((Component)this).transform.Rotate(0f, 300f * Time.deltaTime, 120f * Time.deltaTime, (Space)0);
		}
	}
	public static class NearbyContainers
	{
		private static readonly List<Container> containers = new List<Container>();

		public static Func<Vector3, float, List<Container>>? remoteSources;

		public static Func<Vector3, float, List<StorageSource>>? virtualSources;

		internal static void Register(Container container)
		{
			containers.Add(container);
		}

		internal static List<Container> Find(Vector3 point, float range)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			List<Container> list = FindLocal(point, range);
			if (remoteSources != null)
			{
				foreach (Container item in remoteSources(point, range))
				{
					if ((Object)(object)item != (Object)null && !list.Contains(item))
					{
						list.Add(item);
					}
				}
			}
			return list;
		}

		internal static List<StorageSource> FindSources(Vector3 point, float range)
		{
			//IL_000e: 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)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			List<StorageSource> list = new List<StorageSource>();
			HashSet<ZDOID> hashSet = new HashSet<ZDOID>();
			foreach (Container item in Find(point, range))
			{
				list.Add(new LiveContainerSource(item));
				hashSet.Add(item.m_nview.GetZDO().m_uid);
			}
			if (virtualSources != null)
			{
				foreach (StorageSource item2 in virtualSources(point, range))
				{
					if (item2 != null && hashSet.Add(item2.Id))
					{
						list.Add(item2);
					}
				}
			}
			return list;
		}

		public static List<Container> FindLocal(Vector3 point, float range)
		{
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			containers.RemoveAll((Container c) => (Object)(object)c == (Object)null);
			List<Container> list = new List<Container>();
			long num = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile().GetPlayerID() : 0);
			foreach (Container container in containers)
			{
				if (!((Object)(object)container.m_nview == (Object)null) && container.m_nview.IsValid() && !(Vector3.Distance(((Component)container).transform.position, point) > range) && !container.IsInUse() && container.CheckAccess(num) && (!container.m_checkGuardStone || PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)))
				{
					container.Load();
					list.Add(container);
				}
			}
			return list;
		}

		private static List<StorageSource> FindAroundPlayer(Player player)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			return FindSources(((Component)player).transform.position, Plugin.containerRange.Value);
		}

		internal static int CountItems(Player player, string sharedName, int quality = -1)
		{
			int num = 0;
			foreach (StorageSource item in FindAroundPlayer(player))
			{
				num += item.Inventory.CountItems(sharedName, quality, true);
			}
			return num;
		}

		internal static int RemoveItems(Player player, string sharedName, int amount, int quality = -1, string context = "consume", string? visualPrefab = null)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			int num = amount;
			foreach (StorageSource item in FindAroundPlayer(player))
			{
				if (num <= 0)
				{
					break;
				}
				Inventory inventory = item.Inventory;
				int num2 = inventory.CountItems(sharedName, quality, true);
				if (num2 > 0)
				{
					int num3 = Math.Min(num2, num);
					item.BeginChange();
					inventory.RemoveItem(sharedName, num3, quality, true);
					item.CommitChange();
					num -= num3;
					Plugin.LogPull($"took {num3}x {sharedName} from {Describe(item)} ({context})");
					if (visualPrefab != null)
					{
						FlyingItems.QueueFromContainer(visualPrefab, player, item.Position);
					}
				}
			}
			return amount - num;
		}

		internal static int PullToPlayer(Player player, string sharedName, int amount, string context)
		{
			int num = amount;
			Inventory inventory = ((Humanoid)player).GetInventory();
			foreach (StorageSource item in FindAroundPlayer(player))
			{
				if (num <= 0)
				{
					break;
				}
				Inventory inventory2 = item.Inventory;
				bool flag = false;
				bool flag2 = false;
				foreach (ItemData item2 in new List<ItemData>(inventory2.GetAllItems()))
				{
					if (num <= 0)
					{
						break;
					}
					if (item2.m_shared.m_name != sharedName)
					{
						continue;
					}
					int num2 = Math.Min(item2.m_stack, num);
					item.BeginChange();
					if (num2 >= item2.m_stack)
					{
						if (!inventory.AddItem(item2))
						{
							flag2 = true;
							break;
						}
						inventory2.RemoveItem(item2);
					}
					else
					{
						ItemData val = item2.Clone();
						val.m_stack = num2;
						if (!inventory.AddItem(val))
						{
							flag2 = true;
							break;
						}
						item2.m_stack -= num2;
						inventory2.Changed();
					}
					flag = true;
					num -= num2;
					Plugin.LogPull($"pulled {num2}x {sharedName} from {Describe(item)} ({context})");
				}
				if (flag)
				{
					item.CommitChange();
				}
				if (flag2)
				{
					return amount - num;
				}
			}
			return amount - num;
		}

		private static string Describe(StorageSource source)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//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_003a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = source.Position;
			return $"{source.Name} at ({position.x:0},{position.y:0},{position.z:0})";
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	public static class Container_Awake_RegisterNearby
	{
		private static void Postfix(Container __instance)
		{
			NearbyContainers.Register(__instance);
		}
	}
	[BepInPlugin("org.bepinex.plugins.valheimstorage", "Valheim Storage", "1.3.2")]
	public class Plugin : BaseUnityPlugin
	{
		private const string guid = "org.bepinex.plugins.valheimstorage";

		private const string pluginName = "Valheim Storage";

		private const string version = "1.3.2";

		internal static Plugin instance;

		public static ConfigEntry<float> containerRange;

		public static ConfigEntry<bool> enableCrafting;

		public static ConfigEntry<bool> enableBuilding;

		public static ConfigEntry<bool> enableSmelters;

		public static ConfigEntry<bool> enableFireplaces;

		public static ConfigEntry<bool> enableCookingStations;

		public static ConfigEntry<bool> enableTurrets;

		public static ConfigEntry<string> stationDisallow;

		public static ConfigEntry<string> fuelDisallow;

		public static ConfigEntry<string> oreDisallow;

		public static ConfigEntry<KeyboardShortcut> fillModifier;

		public static ConfigEntry<KeyboardShortcut> pullModifier;

		public static ConfigEntry<KeyboardShortcut> preventModifier;

		public static ConfigEntry<bool> switchPrevent;

		public static ConfigEntry<KeyboardShortcut> favoriteModifier;

		public static ConfigEntry<bool> showAvailable;

		public static ConfigEntry<Color> flashColor;

		public static ConfigEntry<bool> logPulls;

		private void Awake()
		{
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0298: Unknown result type (might be due to invalid IL or missing references)
			instance = this;
			containerRange = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ContainerRange", 20f, "Radius in meters around the player in which chests (and placed backpacks) are used.");
			logPulls = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogPulls", true, "Write an info log entry for every resource pulled from a container, so you can retrace what happened.");
			enableCrafting = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "Crafting", true, "Use containers when crafting and upgrading items at crafting stations.");
			enableBuilding = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "Building", true, "Use containers when building pieces with the hammer.");
			enableSmelters = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "Smelters", true, "Use containers when adding ore and fuel to smelters, kilns, blast furnaces, spinning wheels and windmills.");
			enableFireplaces = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "Fireplaces", true, "Use containers when adding fuel to fires, standing torches, sconces and hearths.");
			enableCookingStations = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "CookingStations", true, "Use containers when cooking food and fueling ovens.");
			enableTurrets = ((BaseUnityPlugin)this).Config.Bind<bool>("Stations", "Turrets", true, "Use containers when reloading ballista turrets.");
			stationDisallow = ((BaseUnityPlugin)this).Config.Bind<string>("Stations", "StationDisallow", "", "Comma separated list of station prefab names that never use containers, no spaces (e.g. piece_workbench,smelter).");
			fuelDisallow = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "FuelDisallowTypes", "", "Comma separated list of fuel item prefab names that are never pulled from containers, no spaces (e.g. RoundLog,FineWood). Does not apply to kilns, which treat wood as ore.");
			oreDisallow = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "OreDisallowTypes", "", "Comma separated list of ore/cookable item prefab names (anything a station transforms) that are never pulled from containers, no spaces.");
			fillModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "FillModifier", new KeyboardShortcut((KeyCode)304, Array.Empty<KeyCode>()), "While held, ore/fuel/ammo is pulled until the station is full instead of one at a time.");
			pullModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "PullModifier", new KeyboardShortcut((KeyCode)306, Array.Empty<KeyCode>()), "While held, station interactions pull the resources into your inventory instead of feeding the station.");
			preventModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "PreventModifier", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "While held, the mod does nothing (vanilla behavior).");
			switchPrevent = ((BaseUnityPlugin)this).Config.Bind<bool>("Keys", "SwitchPrevent", false, "Reverses PreventModifier: the mod only works WHILE the key is held.");
			favoriteModifier = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Keys", "FavoriteModifier", new KeyboardShortcut((KeyCode)308, Array.Empty<KeyCode>()), "Held while left-clicking an inventory item to mark/unmark it as favorite. Favorites are skipped by stack-all and cannot be dropped.");
			showAvailable = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowAvailable", true, "Requirement amounts also show the total available including nearby containers, e.g. \"10 (34)\".");
			flashColor = ((BaseUnityPlugin)this).Config.Bind<Color>("UI", "FlashColor", Color.yellow, "Requirement color when your inventory alone is short but nearby containers cover it.");
			new Harmony("org.bepinex.plugins.valheimstorage").PatchAll(Assembly.GetExecutingAssembly());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Loading [Valheim Storage 1.3.2]");
		}

		internal static void LogPull(string message)
		{
			if (logPulls.Value)
			{
				((BaseUnityPlugin)instance).Logger.LogInfo((object)message);
			}
		}

		internal static bool ModActive()
		{
			//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)
			KeyboardShortcut value = preventModifier.Value;
			bool flag = ((KeyboardShortcut)(ref value)).IsPressed();
			return switchPrevent.Value ? flag : (!flag);
		}

		internal static bool FillMode()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = fillModifier.Value;
			return ((KeyboardShortcut)(ref value)).IsPressed();
		}

		internal static bool PullMode()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = pullModifier.Value;
			return ((KeyboardShortcut)(ref value)).IsPressed();
		}

		internal static bool StationAllowed(GameObject stationObject)
		{
			return !ListContains(stationDisallow.Value, PrefabName(((Object)stationObject).name));
		}

		internal static bool ItemDisallowed(ItemDrop? item, ConfigEntry<string> list)
		{
			return (Object)(object)item != (Object)null && ListContains(list.Value, ((Object)((Component)item).gameObject).name);
		}

		internal static string PrefabName(string gameObjectName)
		{
			int num = gameObjectName.IndexOf('(');
			return (num >= 0) ? gameObjectName.Substring(0, num) : gameObjectName;
		}

		private static bool ListContains(string commaSeparated, string name)
		{
			if (string.IsNullOrEmpty(commaSeparated))
			{
				return false;
			}
			string[] array = commaSeparated.Split(new char[1] { ',' });
			foreach (string text in array)
			{
				if (string.Equals(text.Trim(), name, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	public static class ZNetScene_Awake_RegisterStorageRpc
	{
		private static void Postfix()
		{
			FlyingItems.RegisterRpc();
		}
	}
	public static class QuickStack
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnClick;
		}

		private static GameObject? button;

		internal static void CreateButton(InventoryGui gui)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Expected O, but got Unknown
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)button != (Object)null) && !((Object)(object)gui.m_takeAllButton == (Object)null))
			{
				button = Object.Instantiate<GameObject>(((Component)gui.m_takeAllButton).gameObject, (Transform)(object)gui.m_player);
				((Object)button).name = "VS_QuickStackButton";
				RectTransform val = (RectTransform)button.transform;
				if (Chainloader.PluginInfos.ContainsKey("randyknapp.mods.equipmentandquickslots"))
				{
					val.anchorMin = new Vector2(0f, 1f);
					val.anchorMax = new Vector2(0f, 1f);
					val.pivot = new Vector2(0f, 0.5f);
					val.anchoredPosition = new Vector2(890f, -326f);
				}
				else
				{
					val.anchorMin = new Vector2(1f, 1f);
					val.anchorMax = new Vector2(1f, 1f);
					val.pivot = new Vector2(0f, 1f);
					val.anchoredPosition = new Vector2(12f, -80f);
				}
				Button component = button.GetComponent<Button>();
				component.onClick = new ButtonClickedEvent();
				ButtonClickedEvent onClick = component.onClick;
				object obj = <>O.<0>__OnClick;
				if (obj == null)
				{
					UnityAction val2 = OnClick;
					<>O.<0>__OnClick = val2;
					obj = (object)val2;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj);
				TMP_Text componentInChildren = button.GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = "Stack";
				}
				Sprite val3 = ChestIcon();
				if ((Object)(object)val3 != (Object)null)
				{
					GameObject val4 = new GameObject("Icon", new Type[1] { typeof(RectTransform) });
					val4.transform.SetParent(button.transform, false);
					Image val5 = val4.AddComponent<Image>();
					val5.sprite = val3;
					((Graphic)val5).raycastTarget = false;
					RectTransform val6 = (RectTransform)val4.transform;
					val6.sizeDelta = new Vector2(24f, 24f);
					val6.anchoredPosition = new Vector2(0f, 18f);
				}
			}
		}

		private static Sprite? ChestIcon()
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("piece_chest_wood") : null);
			Piece val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Piece>() : null);
			return ((Object)(object)val2 != (Object)null) ? val2.m_icon : null;
		}

		private static void OnClick()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_dragGo != (Object)null && instance.m_dragItem != null)
			{
				RunSingle(Player.m_localPlayer, instance);
			}
			else
			{
				Run(Player.m_localPlayer);
			}
		}

		private static void RunSingle(Player? player, InventoryGui gui)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			ItemData dragItem = gui.m_dragItem;
			gui.SetupDragItem((ItemData)null, (Inventory)null, 1);
			if ((Object)(object)player == (Object)null || dragItem == null)
			{
				return;
			}
			string name = dragItem.m_shared.m_name;
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = inventory.CountItems(name, -1, true);
			foreach (StorageSource item in NearbyContainers.FindSources(((Component)player).transform.position, Plugin.containerRange.Value))
			{
				Inventory inventory2 = item.Inventory;
				if (!inventory2.ContainsItemByName(name))
				{
					continue;
				}
				item.BeginChange();
				foreach (ItemData item2 in new List<ItemData>(inventory.GetAllItems()))
				{
					if (!(item2.m_shared.m_name != name) && !((Humanoid)player).IsItemEquiped(item2) && (!FavoriteItems.IsFavorite(item2) || item2 == dragItem) && inventory2.AddItem(item2))
					{
						inventory.RemoveItem(item2);
						FlyingItems.Queue(item2, player, item.Position);
					}
				}
				inventory2.Changed();
				item.CommitChange();
			}
			FlyingItems.Flush();
			inventory.Changed();
			int num2 = num - inventory.CountItems(name, -1, true);
			((Character)player).Message((MessageType)2, (num2 > 0) ? $"Stacked {num2} x {name} into nearby containers" : ("No nearby container holds " + name), 0, (Sprite)null);
		}

		internal static void Run(Player? player)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			int num = ((Humanoid)player).GetInventory().CountItems((string)null, -1, true);
			List<ItemData> list = new List<ItemData>(((Humanoid)player).GetInventory().GetAllItems());
			foreach (StorageSource item in NearbyContainers.FindSources(((Component)player).transform.position, Plugin.containerRange.Value))
			{
				item.BeginChange();
				item.Inventory.StackAll(((Humanoid)player).GetInventory(), false);
				item.CommitChange();
				List<ItemData> allItems = ((Humanoid)player).GetInventory().GetAllItems();
				foreach (ItemData item2 in list)
				{
					if (!allItems.Contains(item2))
					{
						FlyingItems.Queue(item2, player, item.Position);
					}
				}
				list = new List<ItemData>(allItems);
			}
			FlyingItems.Flush();
			int num2 = num - ((Humanoid)player).GetInventory().CountItems((string)null, -1, true);
			((Character)player).Message((MessageType)2, (num2 > 0) ? $"Stacked {num2} items into nearby containers" : "Nothing to stack", 0, (Sprite)null);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	public static class InventoryGui_Awake_QuickStackButton
	{
		private static void Postfix(InventoryGui __instance)
		{
			QuickStack.CreateButton(__instance);
		}
	}
	internal static class Feeding
	{
		internal static bool Allowed(ConfigEntry<bool> feature, Component station, Humanoid user)
		{
			return (Object)(object)user == (Object)(object)Player.m_localPlayer && Plugin.ModActive() && feature.Value && Plugin.StationAllowed(station.gameObject);
		}

		internal static string Label(Component station)
		{
			return Plugin.PrefabName(((Object)station.gameObject).name);
		}

		internal static int Borrow(Player player, string sharedName, int want, string context)
		{
			int num = ((Humanoid)player).GetInventory().CountItems(sharedName, -1, true);
			if (num < want)
			{
				num += NearbyContainers.PullToPlayer(player, sharedName, want - num, context);
			}
			return Math.Min(num, want);
		}

		internal static void PullInstead(Player player, ItemDrop item, string context)
		{
			int amount = ((!Plugin.FillMode()) ? 1 : item.m_itemData.m_shared.m_maxStackSize);
			int num = NearbyContainers.PullToPlayer(player, item.m_itemData.m_shared.m_name, amount, context);
			((Character)player).Message((MessageType)2, (num > 0) ? $"Pulled {num}x {item.m_itemData.m_shared.m_name}" : ("$msg_donthaveany " + item.m_itemData.m_shared.m_name), 0, (Sprite)null);
		}
	}
	[HarmonyPatch(typeof(Fireplace), "Interact")]
	public static class Fireplace_Interact_Feed
	{
		private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, ref bool __result)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			if (hold || __instance.m_infiniteFuel || (Object)(object)__instance.m_fuelItem == (Object)null || !Feeding.Allowed(Plugin.enableFireplaces, (Component)(object)__instance, user) || Plugin.ItemDisallowed(__instance.m_fuelItem, Plugin.fuelDisallow))
			{
				return true;
			}
			Player val = (Player)user;
			string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
			string context = "fuel for " + Feeding.Label((Component)(object)__instance);
			if (Plugin.PullMode())
			{
				Feeding.PullInstead(val, __instance.m_fuelItem, context);
				__result = true;
				return false;
			}
			int num = (int)__instance.m_maxFuel - Mathf.CeilToInt(__instance.m_nview.GetZDO().GetFloat(ZDOVars.s_fuel, 0f));
			if (num <= 0)
			{
				return true;
			}
			int num2 = Feeding.Borrow(val, name, (!Plugin.FillMode()) ? 1 : num, context);
			if (Plugin.FillMode() && num2 > 0)
			{
				for (int i = 0; i < num2; i++)
				{
					((Humanoid)val).GetInventory().RemoveItem(name, 1, -1, true);
					__instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
				Plugin.LogPull($"added {num2}x {name} to {Feeding.Label((Component)(object)__instance)}");
				((Character)val).Message((MessageType)2, Localization.instance.Localize("$msg_fireadding", new string[1] { name }), 0, (Sprite)null);
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
	public static class Smelter_OnAddFuel_Feed
	{
		private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ref bool __result)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			if (item != null || (Object)(object)__instance.m_fuelItem == (Object)null || !Feeding.Allowed(Plugin.enableSmelters, (Component)(object)__instance, user) || Plugin.ItemDisallowed(__instance.m_fuelItem, Plugin.fuelDisallow))
			{
				return true;
			}
			Player val = (Player)user;
			string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
			string context = "fuel for " + Feeding.Label((Component)(object)__instance);
			if (Plugin.PullMode())
			{
				Feeding.PullInstead(val, __instance.m_fuelItem, context);
				__result = true;
				return false;
			}
			int num = __instance.m_maxFuel - Mathf.CeilToInt(__instance.GetFuel());
			if (num <= 0)
			{
				return true;
			}
			int num2 = Feeding.Borrow(val, name, (!Plugin.FillMode()) ? 1 : num, context);
			if (Plugin.FillMode() && num2 > 0)
			{
				for (int i = 0; i < num2; i++)
				{
					((Humanoid)val).GetInventory().RemoveItem(name, 1, -1, true);
					__instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
				}
				Plugin.LogPull($"added {num2}x {name} to {Feeding.Label((Component)(object)__instance)}");
				__result = true;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Smelter), "OnAddOre")]
	public static class Smelter_OnAddOre_Feed
	{
		private static bool Prefix(Smelter __instance, Humanoid user, ItemData item, ref bool __result)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (!Feeding.Allowed(Plugin.enableSmelters, (Component)(object)__instance, user))
			{
				return true;
			}
			Player val = (Player)user;
			ItemData val2 = item ?? __instance.FindCookableItem(((Humanoid)val).GetInventory());
			ItemConversion val3 = null;
			if (val2 != null)
			{
				val3 = FindConversion(__instance, val2.m_shared.m_name);
			}
			else
			{
				foreach (ItemConversion item2 in __instance.m_conversion)
				{
					if ((Object)(object)item2.m_from != (Object)null && !Plugin.ItemDisallowed(item2.m_from, Plugin.oreDisallow) && NearbyContainers.CountItems(val, item2.m_from.m_itemData.m_shared.m_name) > 0)
					{
						val3 = item2;
						break;
					}
				}
			}
			if ((Object)(object)val3?.m_from == (Object)null || Plugin.ItemDisallowed(val3.m_from, Plugin.oreDisallow))
			{
				return true;
			}
			string name = val3.m_from.m_itemData.m_shared.m_name;
			string name2 = ((Object)((Component)val3.m_from).gameObject).name;
			string context = "ore for " + Feeding.Label((Component)(object)__instance);
			if (Plugin.PullMode())
			{
				Feeding.PullInstead(val, val3.m_from, context);
				__result = true;
				return false;
			}
			int num = __instance.m_maxOre - __instance.GetQueueSize();
			if (num <= 0)
			{
				return true;
			}
			int num2 = Feeding.Borrow(val, name, (!Plugin.FillMode()) ? 1 : num, context);
			if (Plugin.FillMode() && num2 > 0)
			{
				for (int i = 0; i < num2; i++)
				{
					((Humanoid)val).GetInventory().RemoveItem(name, 1, -1, true);
					__instance.m_nview.InvokeRPC("RPC_AddOre", new object[1] { name2 });
				}
				Plugin.LogPull($"added {num2}x {name} to {Feeding.Label((Component)(object)__instance)}");
				__result = true;
				return false;
			}
			return true;
		}

		private static ItemConversion? FindConversion(Smelter smelter, string sharedName)
		{
			foreach (ItemConversion item in smelter.m_conversion)
			{
				if ((Object)(object)item.m_from != (Object)null && item.m_from.m_itemData.m_shared.m_name == sharedName)
				{
					return item;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(CookingStation), "OnAddFuelSwitch")]
	public static class CookingStation_OnAddFuelSwitch_Feed
	{
		private static bool reentrant;

		private static void Prefix(CookingStation __instance, Humanoid user, ItemData item, ref int __state)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			__state = 0;
			if (!reentrant && item == null && !((Object)(object)__instance.m_fuelItem == (Object)null) && Feeding.Allowed(Plugin.enableCookingStations, (Component)(object)__instance, user) && !Plugin.ItemDisallowed(__instance.m_fuelItem, Plugin.fuelDisallow))
			{
				Player player = (Player)user;
				string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
				int num = __instance.m_maxFuel - Mathf.CeilToInt(__instance.GetFuel());
				if (num > 0)
				{
					int num2 = Feeding.Borrow(player, name, (!Plugin.FillMode()) ? 1 : num, "fuel for " + Feeding.Label((Component)(object)__instance));
					__state = (Plugin.FillMode() ? num2 : 0);
				}
			}
		}

		private static void Postfix(CookingStation __instance, Switch sw, Humanoid user, bool __result, int __state)
		{
			if (reentrant || !__result || __state <= 1)
			{
				return;
			}
			reentrant = true;
			for (int i = 1; i < __state; i++)
			{
				if (!__instance.OnAddFuelSwitch(sw, user, (ItemData)null))
				{
					break;
				}
			}
			reentrant = false;
		}
	}
	[HarmonyPatch(typeof(CookingStation), "OnInteract")]
	public static class CookingStation_OnInteract_Feed
	{
		private static bool reentrant;

		private static void Prefix(CookingStation __instance, Humanoid user)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (!reentrant && Feeding.Allowed(Plugin.enableCookingStations, (Component)(object)__instance, user))
			{
				BorrowCookable(__instance, (Player)user);
			}
		}

		private static void Postfix(CookingStation __instance, Humanoid user, bool __result)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			if (reentrant || !__result || !Plugin.FillMode() || !Feeding.Allowed(Plugin.enableCookingStations, (Component)(object)__instance, user))
			{
				return;
			}
			reentrant = true;
			Player val = (Player)user;
			for (int i = 0; i < 16; i++)
			{
				if (__instance.GetFreeSlot() == -1)
				{
					break;
				}
				if (__instance.FindCookableItem(((Humanoid)val).GetInventory()) == null && !BorrowCookable(__instance, val))
				{
					break;
				}
				if (!__instance.OnInteract(user))
				{
					break;
				}
			}
			reentrant = false;
		}

		private static bool BorrowCookable(CookingStation station, Player player)
		{
			if (station.FindCookableItem(((Humanoid)player).GetInventory()) != null)
			{
				return true;
			}
			foreach (ItemConversion item in station.m_conversion)
			{
				if (!((Object)(object)item.m_from == (Object)null) && !Plugin.ItemDisallowed(item.m_from, Plugin.oreDisallow))
				{
					string name = item.m_from.m_itemData.m_shared.m_name;
					if (NearbyContainers.PullToPlayer(player, name, 1, "food for " + Feeding.Label((Component)(object)station)) > 0)
					{
						return true;
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Turret), "Interact")]
	public static class Turret_Interact_Feed
	{
		private static bool Prefix(Turret __instance, Humanoid character, bool hold, ref bool __result)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			if (hold || !Feeding.Allowed(Plugin.enableTurrets, (Component)(object)__instance, character))
			{
				return true;
			}
			Player val = (Player)character;
			foreach (AmmoType item in __instance.m_allowedAmmo)
			{
				if ((Object)(object)item.m_ammo == (Object)null)
				{
					continue;
				}
				string name = item.m_ammo.m_itemData.m_shared.m_name;
				if (NearbyContainers.CountItems(val, name) <= 0 && ((Humanoid)val).GetInventory().CountItems(name, -1, true) <= 0)
				{
					continue;
				}
				string context = "ammo for " + Feeding.Label((Component)(object)__instance);
				if (Plugin.PullMode())
				{
					Feeding.PullInstead(val, item.m_ammo, context);
					__result = true;
					return false;
				}
				int num = ((__instance.m_maxAmmo <= 0) ? 1 : (__instance.m_maxAmmo - __instance.GetAmmo()));
				if (num <= 0)
				{
					return true;
				}
				Feeding.Borrow(val, name, (!Plugin.FillMode()) ? 1 : num, context);
				return true;
			}
			return true;
		}
	}
	public abstract class StorageSource
	{
		public abstract Inventory Inventory { get; }

		public abstract Vector3 Position { get; }

		public abstract string Name { get; }

		public abstract ZDOID Id { get; }

		public abstract void BeginChange();

		public abstract void CommitChange();
	}
	public sealed class LiveContainerSource : StorageSource
	{
		private readonly Container container;

		public override Inventory Inventory => container.GetInventory();

		public override Vector3 Position => ((Component)container).transform.position;

		public override string Name => Plugin.PrefabName(((Object)((Component)container).gameObject).name);

		public override ZDOID Id => container.m_nview.GetZDO().m_uid;

		public LiveContainerSource(Container container)
		{
			this.container = container;
		}

		public override void BeginChange()
		{
			container.m_nview.ClaimOwnership();
		}

		public override void CommitChange()
		{
		}
	}
}
namespace MovableValheimStorageStack
{
	[BepInPlugin("valheimstorage.movablestackbutton", "Movable ValheimStorage Stack Button", "1.1.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private const string PluginGuid = "valheimstorage.movablestackbutton";

		private const string PluginName = "Movable ValheimStorage Stack Button";

		private const string PluginVersion = "1.1.0";

		private ConfigEntry<bool> _hasSavedPosition;

		private ConfigEntry<float> _savedX;

		private ConfigEntry<float> _savedY;

		private RectTransform _button;

		private bool _dragging;

		private Vector2 _lastMousePosition;

		private void Awake()
		{
			_hasSavedPosition = ((BaseUnityPlugin)this).Config.Bind<bool>("Position", "Saved", false, "Whether a custom Stack-button position has been saved.");
			_savedX = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "X", 0f, "Saved X position of the ValheimStorage Stack button.");
			_savedY = ((BaseUnityPlugin)this).Config.Bind<float>("Position", "Y", 0f, "Saved Y position of the ValheimStorage Stack button.");
		}

		private void Update()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: 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)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			EnsureButton();
			if (!((Object)(object)_button == (Object)null))
			{
				Vector2 val = Vector2.op_Implicit(Input.mousePosition);
				if (!_dragging && Input.GetMouseButtonDown(1) && IsMouseOverButton(val))
				{
					_dragging = true;
					_lastMousePosition = val;
				}
				if (_dragging && Input.GetMouseButton(1))
				{
					Vector2 val2 = val - _lastMousePosition;
					_lastMousePosition = val;
					Canvas componentInParent = ((Component)_button).GetComponentInParent<Canvas>();
					float num = (((Object)(object)componentInParent != (Object)null && componentInParent.scaleFactor > 0f) ? componentInParent.scaleFactor : 1f);
					RectTransform button = _button;
					button.anchoredPosition += val2 / num;
				}
				if (_dragging && Input.GetMouseButtonUp(1))
				{
					_dragging = false;
					Vector2 anchoredPosition = _button.anchoredPosition;
					_savedX.Value = anchoredPosition.x;
					_savedY.Value = anchoredPosition.y;
					_hasSavedPosition.Value = true;
				}
			}
		}

		private void EnsureButton()
		{
			if ((Object)(object)_button != (Object)null)
			{
				return;
			}
			Button[] array = Resources.FindObjectsOfTypeAll<Button>();
			foreach (Button val in array)
			{
				if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !((Component)val).gameObject.activeInHierarchy)
				{
					continue;
				}
				string text = ((Object)((Component)val).gameObject).name ?? "";
				if (text.IndexOf("stack", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					SetButton(((Component)val).GetComponent<RectTransform>());
					if ((Object)(object)_button != (Object)null)
					{
						break;
					}
				}
				Text[] componentsInChildren = ((Component)val).GetComponentsInChildren<Text>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					string text2 = (((Object)(object)componentsInChildren[j] != (Object)null) ? componentsInChildren[j].text : null);
					if (!string.IsNullOrEmpty(text2) && text2.IndexOf("stack", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						SetButton(((Component)val).GetComponent<RectTransform>());
						if ((Object)(object)_button != (Object)null)
						{
							return;
						}
					}
				}
			}
		}

		private void SetButton(RectTransform rect)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rect == (Object)null))
			{
				_button = rect;
				if (_hasSavedPosition.Value)
				{
					_button.anchoredPosition = new Vector2(_savedX.Value, _savedY.Value);
				}
			}
		}

		private bool IsMouseOverButton(Vector2 mousePosition)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			Canvas componentInParent = ((Component)_button).GetComponentInParent<Canvas>();
			Camera val = null;
			if ((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0)
			{
				val = componentInParent.worldCamera;
			}
			return RectTransformUtility.RectangleContainsScreenPoint(_button, mousePosition, val);
		}
	}
}