Decompiled source of RestlessPiles v0.1.6

RestlessPiles.dll

Decompiled 13 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using RestlessQoL.Api;
using RestlessQoL.Core;
using RestlessQoL.HudTweaks;
using RestlessQoL.Storage;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("RestlessPiles")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.6.0")]
[assembly: AssemblyInformationalVersion("0.1.6+b108291e4de755d164c1385424756b2ee56266dd")]
[assembly: AssemblyProduct("RestlessPiles")]
[assembly: AssemblyTitle("RestlessPiles")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.6.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 RestlessPiles
{
	internal static class Pile
	{
		private const string CountKey = "restless.stored";

		private const string LongKey = "restless.pile";

		public static bool IsPilePrefab(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			if (!name.EndsWith("_stack", StringComparison.Ordinal))
			{
				return name.EndsWith("_pile", StringComparison.Ordinal);
			}
			return true;
		}

		public static bool TryKind(GameObject go, out Piece piece, out ItemData item)
		{
			piece = (((Object)(object)go != (Object)null) ? go.GetComponent<Piece>() : null);
			item = null;
			if (piece?.m_resources == null || piece.m_resources.Length == 0)
			{
				return false;
			}
			if (!IsPilePrefab(Utils.GetPrefabName(go)))
			{
				return false;
			}
			item = piece.m_resources[0].m_resItem?.m_itemData;
			if (item?.m_shared != null)
			{
				return item.m_shared.m_maxStackSize > 1;
			}
			return false;
		}

		public static PileBox? TryAttach(GameObject go)
		{
			if (!TryKind(go, out Piece _, out ItemData _))
			{
				if (!((Object)(object)go != (Object)null))
				{
					return null;
				}
				return go.GetComponent<PileBox>();
			}
			PileBox component = go.GetComponent<PileBox>();
			if (!((Object)(object)component != (Object)null))
			{
				return go.AddComponent<PileBox>();
			}
			return component;
		}

		public static int Count(ZNetView view)
		{
			ZDO val = (((Object)(object)view != (Object)null && view.IsValid()) ? view.GetZDO() : null);
			if (val == null)
			{
				return 0;
			}
			long num = val.GetLong("restless.pile", -1L);
			if (num >= 0)
			{
				if (num <= int.MaxValue)
				{
					return (int)num;
				}
				return int.MaxValue;
			}
			return val.GetInt("restless.stored", 0);
		}

		public static void Write(ZNetView view, int stack)
		{
			if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner())
			{
				ZDO zDO = view.GetZDO();
				if (zDO != null)
				{
					int num = Mathf.Max(0, stack);
					zDO.Set("restless.pile", (long)num);
					zDO.Set("restless.stored", num);
				}
			}
		}

		public static void OwnThen(ZNetView view, Action<ZNetView> act, Action? fail = null)
		{
			if ((Object)(object)view == (Object)null || !view.IsValid())
			{
				fail?.Invoke();
				return;
			}
			if (view.IsOwner())
			{
				act(view);
				return;
			}
			view.ClaimOwnership();
			((MonoBehaviour)Plugin.Instance).StartCoroutine(WaitOwn(view, act, fail));
		}

		private static IEnumerator WaitOwn(ZNetView view, Action<ZNetView> act, Action? fail)
		{
			float until = Time.time + 1.5f;
			while ((Object)(object)view != (Object)null && view.IsValid() && !view.IsOwner() && Time.time < until)
			{
				yield return null;
			}
			if ((Object)(object)view != (Object)null && view.IsValid() && view.IsOwner())
			{
				act(view);
			}
			else
			{
				fail?.Invoke();
			}
		}

		public static string Title(ItemData item)
		{
			string text = item?.m_shared?.m_name ?? "";
			if (Localization.instance != null)
			{
				text = Localization.instance.Localize(text);
			}
			return RestlessUi.Bare(text);
		}

		public static string PieceTitle(Piece piece)
		{
			string text = piece?.m_name ?? "";
			if (Localization.instance != null)
			{
				text = Localization.instance.Localize(text);
			}
			return RestlessUi.Bare(text);
		}
	}
	internal static class PileBag
	{
		private static float _nextVacuum;

		public static bool Matches(ItemData? a, ItemData? b)
		{
			if (a?.m_shared == null || b?.m_shared == null)
			{
				return false;
			}
			return a.m_shared.m_name == b.m_shared.m_name;
		}

		public static int TakeStack(Player player, PileBox box)
		{
			int taken = 0;
			Pile.OwnThen(box.View, delegate
			{
				taken = TakeOwned(player, box, 0);
			});
			return taken;
		}

		public static int CountNearby(string sharedName)
		{
			//IL_0086: 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_0096: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || string.IsNullOrEmpty(sharedName) || !PileConfig.On)
			{
				return 0;
			}
			float nearby = PileConfig.Nearby;
			int num = 0;
			foreach (PileBox item in PileBox.All)
			{
				if (!((Object)(object)item == (Object)null) && item.Live && item.Item?.m_shared != null && !(item.Item.m_shared.m_name != sharedName))
				{
					Vector3 val = ((Component)item).transform.position - ((Component)localPlayer).transform.position;
					if (!(((Vector3)(ref val)).sqrMagnitude > nearby * nearby))
					{
						num += item.Stored;
					}
				}
			}
			return num;
		}

		public static bool TryCloneNearby(ItemDrop drop, out ItemData item)
		{
			//IL_00bd: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			item = null;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || drop?.m_itemData?.m_shared == null || !PileConfig.On)
			{
				return false;
			}
			float nearby = PileConfig.Nearby;
			string name = drop.m_itemData.m_shared.m_name;
			foreach (PileBox item2 in PileBox.All)
			{
				if (!((Object)(object)item2 == (Object)null) && item2.Live && item2.Stored > 0 && item2.Item?.m_shared != null && !(item2.Item.m_shared.m_name != name))
				{
					Vector3 val = ((Component)item2).transform.position - ((Component)localPlayer).transform.position;
					if (!(((Vector3)(ref val)).sqrMagnitude > nearby * nearby))
					{
						item = item2.Item.Clone();
						item.m_stack = 1;
						return NearbyStorage.EnsureDropPrefab(item, drop);
					}
				}
			}
			return false;
		}

		public static int ConsumeNearby(string sharedName, int amount)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || amount <= 0 || !PileConfig.On)
			{
				return 0;
			}
			float nearby = PileConfig.Nearby;
			int num = 0;
			foreach (PileBox item in PileBox.All)
			{
				if (num >= amount)
				{
					break;
				}
				if ((Object)(object)item == (Object)null || !item.Live || item.Item?.m_shared == null || item.Item.m_shared.m_name != sharedName)
				{
					continue;
				}
				Vector3 val = ((Component)item).transform.position - ((Component)localPlayer).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > nearby * nearby))
				{
					if (!item.View.IsOwner())
					{
						item.View.ClaimOwnership();
					}
					if (item.View.IsOwner())
					{
						num += PullFromPile(item, amount - num);
					}
				}
			}
			return num;
		}

		private static int PullFromPile(PileBox box, int amount)
		{
			if ((Object)(object)box == (Object)null || amount <= 0 || box.Stored <= 0)
			{
				return 0;
			}
			int num = Mathf.Min(amount, box.Stored);
			Pile.Write(box.View, box.Stored - num);
			return num;
		}

		private static int TakeOwned(Player player, PileBox box, int limit)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)box == (Object)null || box.Stored <= 0)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			ItemData item = box.Item;
			if (inventory == null || item?.m_shared == null)
			{
				return 0;
			}
			int maxStackSize = item.m_shared.m_maxStackSize;
			int num = ((limit > 0) ? Mathf.Min(limit, box.Stored) : box.Stored);
			ItemData val = RoomInBag(inventory, item);
			int num2;
			if (val != null)
			{
				num2 = Mathf.Min(maxStackSize - val.m_stack, num);
			}
			else
			{
				if (!inventory.HaveEmptySlot())
				{
					if (limit <= 0)
					{
						((Character)player).Message((MessageType)2, "Bag is full", 0, (Sprite)null, false);
					}
					return 0;
				}
				num2 = Mathf.Min(maxStackSize, num);
			}
			if (num2 <= 0)
			{
				return 0;
			}
			if (val != null)
			{
				val.m_stack += num2;
			}
			else
			{
				ItemData val2 = item.Clone();
				val2.m_stack = num2;
				val2.m_cheated = false;
				if (!inventory.AddItem(val2))
				{
					if (limit <= 0)
					{
						((Character)player).Message((MessageType)2, "Bag is full", 0, (Sprite)null, false);
					}
					return 0;
				}
			}
			inventory.Changed(true, false);
			Pile.Write(box.View, box.Stored - num2);
			if (limit <= 0)
			{
				Tell(player, "Took " + num2 + " " + Pile.Title(item), num2, item);
			}
			return num2;
		}

		private static ItemData? RoomInBag(Inventory inv, ItemData item)
		{
			foreach (ItemData allItem in inv.GetAllItems())
			{
				if (allItem?.m_shared != null && !(allItem.m_shared.m_name != item.m_shared.m_name) && allItem.m_stack < allItem.m_shared.m_maxStackSize)
				{
					return allItem;
				}
			}
			return null;
		}

		public static int DumpInto(Player player, PileBox box)
		{
			int moved = 0;
			Pile.OwnThen(box.View, delegate
			{
				moved = DumpOwned(player, box);
			});
			return moved;
		}

		private static int DumpOwned(Player player, PileBox box)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)box == (Object)null)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			int num = 0;
			ItemData[] array = inventory.GetAllItems().ToArray();
			foreach (ItemData val in array)
			{
				if (CanDump(val) && Matches(val, box.Item))
				{
					num += val.m_stack;
					inventory.RemoveItem(val);
				}
			}
			if (num <= 0)
			{
				return 0;
			}
			inventory.Changed(true, false);
			Pile.Write(box.View, box.Stored + num);
			Tell(player, "Stacked " + num + " " + Pile.Title(box.Item), num, box.Item);
			return num;
		}

		public static int DumpNearby(Player player)
		{
			//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_005d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return 0;
			}
			Vector3 position = ((Component)player).transform.position;
			float nearby = PileConfig.Nearby;
			int num = 0;
			ItemData val = null;
			Dictionary<PileBox, (int, ItemData)> dictionary = new Dictionary<PileBox, (int, ItemData)>();
			ItemData[] array = inventory.GetAllItems().ToArray();
			foreach (ItemData val2 in array)
			{
				if (!CanDump(val2))
				{
					continue;
				}
				PileBox pileBox = Nearest(position, nearby, val2);
				if (!((Object)(object)pileBox == (Object)null))
				{
					int stack = val2.m_stack;
					ItemData val3 = val2.Clone();
					val3.m_stack = stack;
					inventory.RemoveItem(val2);
					num += stack;
					val = val3;
					if (dictionary.TryGetValue(pileBox, out var value))
					{
						dictionary[pileBox] = (value.Item1 + stack, value.Item2);
					}
					else
					{
						dictionary[pileBox] = (stack, val3);
					}
				}
			}
			foreach (KeyValuePair<PileBox, (int, ItemData)> item in dictionary)
			{
				PileBox dest = item.Key;
				int n = item.Value.Item1;
				ItemData sample = item.Value.Item2;
				Pile.OwnThen(dest.View, delegate(ZNetView view)
				{
					Pile.Write(view, Pile.Count(view) + n);
				}, delegate
				{
					dest.DropStacks(sample, n);
				});
			}
			if (num <= 0)
			{
				return 0;
			}
			inventory.Changed(true, false);
			if (val != null)
			{
				Tell(player, "Stacked " + num + " into piles", num, val);
			}
			return num;
		}

		public static void VacuumNearby(Player player)
		{
			//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_00c2: 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_00c8: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || !PileConfig.On || Time.time < _nextVacuum)
			{
				return;
			}
			_nextVacuum = Time.time + ModConfig.VacuumInterval.Value;
			Vector3 position = ((Component)player).transform.position;
			float nearby = PileConfig.Nearby;
			ItemDrop[] array = ItemDrop.s_instances.ToArray();
			foreach (ItemDrop val in array)
			{
				if (val?.m_itemData?.m_shared == null || (Object)(object)val.m_nview == (Object)null || !val.m_nview.IsValid() || val.m_itemData.m_shared.m_questItem || !val.CanPickup(false))
				{
					continue;
				}
				Vector3 val2 = ((Component)val).transform.position - position;
				if (((Vector3)(ref val2)).sqrMagnitude > nearby * nearby)
				{
					continue;
				}
				PileBox pileBox = Nearest(position, nearby, val.m_itemData);
				if (!((Object)(object)pileBox == (Object)null))
				{
					ZDOID uid = val.m_nview.GetZDO().m_uid;
					if (NearbyStorage.BeginDeposit(uid))
					{
						((MonoBehaviour)Plugin.Instance).StartCoroutine(AbsorbDrop(val, pileBox, uid));
					}
				}
			}
		}

		private static IEnumerator AbsorbDrop(ItemDrop drop, PileBox box, ZDOID id)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)box == (Object)null || !box.Live)
				{
					yield break;
				}
				if (!box.View.IsOwner())
				{
					box.View.ClaimOwnership();
					float until = Time.time + 1.5f;
					while ((Object)(object)box != (Object)null && box.Live && !box.View.IsOwner() && Time.time < until)
					{
						yield return null;
					}
				}
				if ((Object)(object)box == (Object)null || !box.Live || !box.View.IsOwner() || (Object)(object)drop == (Object)null || (Object)(object)drop.m_nview == (Object)null || !drop.m_nview.IsValid())
				{
					yield break;
				}
				if (!drop.m_nview.IsOwner())
				{
					drop.m_nview.ClaimOwnership();
					float until = Time.time + 1.5f;
					while ((Object)(object)drop != (Object)null && (Object)(object)drop.m_nview != (Object)null && drop.m_nview.IsValid() && !drop.m_nview.IsOwner() && Time.time < until)
					{
						yield return null;
					}
				}
				if (!((Object)(object)drop == (Object)null) && !((Object)(object)drop.m_nview == (Object)null) && drop.m_nview.IsValid() && drop.m_nview.IsOwner() && drop.m_itemData != null && drop.m_itemData.m_stack > 0 && Matches(drop.m_itemData, box.Item))
				{
					int stack = drop.m_itemData.m_stack;
					Pile.Write(box.View, box.Stored + stack);
					drop.m_nview.Destroy();
				}
			}
			finally
			{
				NearbyStorage.EndDeposit(id);
			}
		}

		private static bool CanDump(ItemData? item)
		{
			if (item?.m_shared == null || item.m_equipped || item.m_stack <= 0)
			{
				return false;
			}
			if (item.m_shared.m_maxStackSize <= 1 || item.m_shared.m_questItem)
			{
				return false;
			}
			if (!ExtraSlots.SkipDeposit(item))
			{
				return !SlotLock.Held(item);
			}
			return false;
		}

		private static PileBox? Nearest(Vector3 origin, float range, ItemData item)
		{
			//IL_0040: 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_0046: 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)
			PileBox result = null;
			float num = range * range;
			foreach (PileBox item2 in PileBox.All)
			{
				if (!((Object)(object)item2 == (Object)null) && item2.Live && Matches(item2.Item, item))
				{
					Vector3 val = ((Component)item2).transform.position - origin;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude > num))
					{
						num = sqrMagnitude;
						result = item2;
					}
				}
			}
			return result;
		}

		private static void Tell(Player player, string text, int amount, ItemData item)
		{
			if (ModConfig.NoticesEnabled.Value)
			{
				Notices.Post(text, amount, RestlessUi.IconOf(item));
			}
			else
			{
				((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	public sealed class PileBox : MonoBehaviour, Interactable, Hoverable
	{
		internal static readonly List<PileBox> All = new List<PileBox>();

		private ZNetView _view;

		private Piece _piece;

		private ItemData _item;

		public ZNetView View => _view;

		public Piece Piece => _piece;

		public ItemData Item => _item;

		public int Stored => Pile.Count(_view);

		internal bool Live
		{
			get
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				if (((Behaviour)this).isActiveAndEnabled)
				{
					Scene scene = ((Component)this).gameObject.scene;
					if (((Scene)(ref scene)).IsValid() && (Object)(object)_view != (Object)null)
					{
						return _view.IsValid();
					}
				}
				return false;
			}
		}

		private void Awake()
		{
			_view = ((Component)this).GetComponent<ZNetView>();
			if (!Pile.TryKind(((Component)this).gameObject, out _piece, out _item))
			{
				((Behaviour)this).enabled = false;
			}
		}

		private void OnEnable()
		{
			Register();
		}

		private void Start()
		{
			Register();
		}

		private void OnDisable()
		{
			All.Remove(this);
		}

		private void Register()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (((Behaviour)this).isActiveAndEnabled)
			{
				Scene scene = ((Component)this).gameObject.scene;
				if (((Scene)(ref scene)).IsValid() && !All.Contains(this))
				{
					All.Add(this);
				}
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (!PileConfig.On || hold || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (alt)
			{
				PileBag.TakeStack(Player.m_localPlayer, this);
				return true;
			}
			PileUi.Open(this);
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			if (!PileConfig.On || (Object)(object)user != (Object)(object)Player.m_localPlayer || !PileBag.Matches(item, _item))
			{
				return false;
			}
			PileBag.DumpInto(Player.m_localPlayer, this);
			return true;
		}

		public string GetHoverText()
		{
			if (!PileConfig.On)
			{
				return GetHoverName();
			}
			return Localization.instance.Localize(GetHoverName() + " x" + Stored + "\n[<color=yellow><b>$KEY_Use</b></color>] Open\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Take stack");
		}

		public string GetHoverName()
		{
			string text = Pile.PieceTitle(_piece);
			if (text.Length <= 0)
			{
				return Pile.Title(_item);
			}
			return text;
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		internal void Spill(bool includeBuildCost)
		{
			if ((Object)(object)_view == (Object)null || !_view.IsValid())
			{
				return;
			}
			if (!_view.IsOwner())
			{
				_view.ClaimOwnership();
			}
			if (!_view.IsOwner())
			{
				return;
			}
			int stored = Stored;
			Pile.Write(_view, 0);
			DropStacks(_item, stored);
			if (!includeBuildCost || _piece?.m_resources == null)
			{
				return;
			}
			Requirement[] resources = _piece.m_resources;
			foreach (Requirement val in resources)
			{
				if (val != null && val.m_amount > 0)
				{
					ItemData val2 = val.m_resItem?.m_itemData;
					if (val2?.m_shared != null)
					{
						DropStacks(val2, val.m_amount);
					}
				}
			}
		}

		internal void DropStacks(ItemData item, int amount)
		{
			//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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (item?.m_shared == null || amount <= 0)
			{
				return;
			}
			NearbyStorage.EnsureDropPrefab(item, (ItemDrop)null);
			if (!((Object)(object)item.m_dropPrefab == (Object)null))
			{
				int num = Mathf.Max(1, item.m_shared.m_maxStackSize);
				Vector3 val = ((Component)this).transform.position + Vector3.up * 0.5f;
				int num2 = amount;
				while (num2 > 0)
				{
					int num3 = Mathf.Min(num, num2);
					ItemDrop.DropItem(item, num3, val, Quaternion.identity);
					num2 -= num3;
				}
			}
		}
	}
	internal static class PileConfig
	{
		private static readonly ConfigurationManagerAttributes Admin = new ConfigurationManagerAttributes
		{
			IsAdminOnly = true
		};

		public static ConfigEntry<bool> Enabled = null;

		public static ConfigEntry<bool> Isolate = null;

		public static ConfigEntry<float> Range = null;

		public static bool On => Enabled.Value;

		public static float Nearby
		{
			get
			{
				if (!Isolate.Value)
				{
					return ModConfig.StorageRange.Value;
				}
				return Range.Value;
			}
		}

		public static void Bind(ConfigFile config)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			Enabled = config.Bind<bool>("Piles", "Enabled", true, new ConfigDescription("Vanilla wood stacks / stone piles (and the other resource piles) open as uncapped single-item stores. Host-locked.", (AcceptableValueBase)null, new object[1] { Admin }));
			Isolate = config.Bind<bool>("Piles", "IsolateRange", false, new ConfigDescription("Use Pile range below instead of Core Search range for ` , vacuum, craft, and station pull from piles. Host-locked.", (AcceptableValueBase)null, new object[1] { Admin }));
			Range = config.Bind<float>("Piles", "Range", 10f, new ConfigDescription("How far piles reach when Isolate pile range is on. Ignored otherwise — piles use Core Search range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 30f), new object[1] { Admin }));
		}
	}
	[HarmonyPatch]
	internal static class PilePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static void AfterScene(ZNetScene __instance)
		{
			if (__instance?.m_prefabs == null)
			{
				return;
			}
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				Pile.TryAttach(prefab);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Piece), "Awake")]
		private static void AfterPiece(Piece __instance)
		{
			Pile.TryAttach(((Component)__instance).gameObject);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(WearNTear), "Destroy", new Type[]
		{
			typeof(HitData),
			typeof(bool)
		})]
		private static void BeforeDestroy(WearNTear __instance, ref bool blockDrop)
		{
			PileBox pileBox = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<PileBox>() : null);
			if (!((Object)(object)pileBox == (Object)null))
			{
				bool includeBuildCost = !blockDrop;
				pileBox.Spill(includeBuildCost);
				blockDrop = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(HoverText), "GetHoverText")]
		private static void AfterHoverLabel(HoverText __instance, ref string __result)
		{
			PileBox componentInParent = ((Component)__instance).GetComponentInParent<PileBox>();
			if ((Object)(object)componentInParent != (Object)null && PileConfig.On)
			{
				__result = componentInParent.GetHoverText();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(QuickStack), "Run")]
		private static void BeforeQuickStack(Player player)
		{
			if (PileConfig.On)
			{
				PileBag.DumpNearby(player);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GroundVacuum), "Tick")]
		private static void BeforeVacuum()
		{
			if (PileConfig.On)
			{
				PileBag.VacuumNearby(Player.m_localPlayer);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(NearbyStorage), "Count")]
		private static void AfterCount(string sharedName, ref int __result)
		{
			if (PileConfig.On)
			{
				__result += PileBag.CountNearby(sharedName);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(NearbyStorage), "TryConsume")]
		private static void AfterConsume(string sharedName, int amount, ref int __result)
		{
			if (PileConfig.On && __result < amount)
			{
				__result += PileBag.ConsumeNearby(sharedName, amount - __result);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(NearbyStorage), "TryCloneIfPresent")]
		private static void AfterTryCloneIfPresent(ItemDrop drop, ref ItemData item, ref bool __result)
		{
			if (!__result && PileConfig.On)
			{
				__result = PileBag.TryCloneNearby(drop, out item);
			}
		}
	}
	internal static class PileSettings
	{
		internal static IDisposable Register()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			return SettingsPageApi.RegisterSettings("restless.piles", (SettingsSection[])(object)new SettingsSection[1]
			{
				new SettingsSection("Resource piles", (SettingsOption[])(object)new SettingsOption[3]
				{
					new SettingsOption("Enable RestlessPiles", (ConfigEntryBase)(object)PileConfig.Enabled, true, "", false),
					new SettingsOption("Isolate pile range", (ConfigEntryBase)(object)PileConfig.Isolate, true, "", false),
					new SettingsOption("Pile range", (ConfigEntryBase)(object)PileConfig.Range, true, "m", false, (Func<bool>)(() => PileConfig.Isolate.Value))
				})
			});
		}
	}
	internal static class PileUi
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__20_0;

			public static UnityAction <>9__20_1;

			internal void <Ensure>b__20_0()
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && (Object)(object)_box != (Object)null)
				{
					PileBag.TakeStack(localPlayer, _box);
				}
			}

			internal void <Ensure>b__20_1()
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && (Object)(object)_box != (Object)null)
				{
					PileBag.DumpInto(localPlayer, _box);
				}
			}
		}

		private const float Width = 360f;

		private const float Height = 228f;

		private const float Reach = 4f;

		private static GameObject? _root;

		private static GameObject? _tray;

		private static GameObject? _slot;

		private static Image? _icon;

		private static Text? _title;

		private static Text? _meta;

		private static PileBox? _box;

		private static float _opened;

		private static bool _blocked;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_root != (Object)null && _root.activeSelf)
				{
					return (Object)(object)_box != (Object)null;
				}
				return false;
			}
		}

		public static void Open(PileBox box)
		{
			if ((Object)(object)box == (Object)null || !((Behaviour)box).isActiveAndEnabled)
			{
				return;
			}
			if (IsOpen && (Object)(object)_box == (Object)(object)box && Time.unscaledTime - _opened > 0.2f)
			{
				Close();
				return;
			}
			_box = box;
			_opened = Time.unscaledTime;
			Ensure();
			if (!((Object)(object)_root == (Object)null))
			{
				_root.SetActive(true);
				Block(on: true);
				FreeCursor();
				Refresh();
			}
		}

		public static void Close()
		{
			_box = null;
			Block(on: false);
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
			}
		}

		public static void TearDown()
		{
			Block(on: false);
			if ((Object)(object)_root != (Object)null)
			{
				Object.Destroy((Object)(object)_root);
			}
			_root = null;
			_tray = null;
			_slot = null;
			_icon = null;
			_title = null;
			_meta = null;
			_box = null;
		}

		public static void Tick()
		{
			//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_0073: Unknown result type (might be due to invalid IL or missing references)
			if (!IsOpen)
			{
				return;
			}
			if (!PileConfig.On || (Object)(object)Player.m_localPlayer == (Object)null || RestlessUi.MapOpen() || RestlessUi.InventoryOpen() || Menu.IsVisible() || (Object)(object)_box == (Object)null || !((Behaviour)_box).isActiveAndEnabled)
			{
				Close();
				return;
			}
			Vector3 val = ((Component)Player.m_localPlayer).transform.position - ((Component)_box).transform.position;
			if (((Vector3)(ref val)).sqrMagnitude > 16f)
			{
				Close();
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
				return;
			}
			FreeCursor();
			Refresh();
		}

		private static void Block(bool on)
		{
			if (on != _blocked)
			{
				GUIManager.BlockInput(on);
				_blocked = on;
				if (on)
				{
					FreeCursor();
				}
			}
		}

		private static void FreeCursor()
		{
			Cursor.lockState = (CursorLockMode)0;
			Cursor.visible = true;
		}

		private static void Ensure()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: 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)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: 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_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Expected O, but got Unknown
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_031b: Expected O, but got Unknown
			object obj;
			if (!((Object)(object)GUIManager.CustomGUIFront != (Object)null))
			{
				Hud instance = Hud.instance;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					GameObject rootObject = instance.m_rootObject;
					obj = ((rootObject != null) ? rootObject.transform : null);
				}
			}
			else
			{
				obj = GUIManager.CustomGUIFront.transform;
			}
			Transform val = (Transform)obj;
			if ((Object)(object)val == (Object)null || (Object)(object)_root != (Object)null)
			{
				return;
			}
			_root = RestlessUi.Node(val, "RestlessPile");
			RestlessUi.Place(_root, (HudDock)0, new Vector2(360f, 228f), new Vector2(0f, 36f));
			_tray = RestlessUi.Tray(_root.transform, "tray", true);
			RestlessUi.Stretch(_tray, Vector2.zero, Vector2.one, Vector2.zero, Vector2.zero);
			RestlessUi.PaperSurface(_tray, false, (Color?)null);
			RestlessUi.PaperCorner(_tray);
			RestlessUi.PaperControl(_tray, (Color?)null);
			_title = RestlessUi.Label(_tray.transform, "", 32, RestlessUi.Text, (TextAnchor)3);
			RestlessUi.Pin(((Component)_title).gameObject, new Vector2(0f, 1f), new Vector2(0f, 1f), new Vector2(28f, -18f), new Vector2(304f, 36f));
			RestlessUi.TitleTear(_tray, ((Graphic)_title).rectTransform);
			_slot = RestlessUi.Graphic(_tray.transform, "slot", Color.clear, false);
			RestlessUi.Pin(_slot, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 16f), new Vector2(72f, 72f));
			GameObject obj2 = RestlessUi.Graphic(_slot.transform, "icon", Color.white, false);
			RestlessUi.Stretch(obj2, Vector2.zero, Vector2.one, new Vector2(10f, 10f), new Vector2(-10f, -10f));
			_icon = obj2.GetComponent<Image>();
			_icon.preserveAspect = true;
			_meta = RestlessUi.Label(_tray.transform, "", 18, RestlessUi.Muted, (TextAnchor)4);
			RestlessUi.Pin(((Component)_meta).gameObject, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, -36f), new Vector2(312f, 24f));
			Vector2 pos = new Vector2(-78f, 22f);
			object obj3 = <>c.<>9__20_0;
			if (obj3 == null)
			{
				UnityAction val2 = delegate
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer != (Object)null && (Object)(object)_box != (Object)null)
					{
						PileBag.TakeStack(localPlayer, _box);
					}
				};
				<>c.<>9__20_0 = val2;
				obj3 = (object)val2;
			}
			Button("take", "Take stack", pos, (UnityAction)obj3);
			Vector2 pos2 = new Vector2(78f, 22f);
			object obj4 = <>c.<>9__20_1;
			if (obj4 == null)
			{
				UnityAction val3 = delegate
				{
					Player localPlayer = Player.m_localPlayer;
					if ((Object)(object)localPlayer != (Object)null && (Object)(object)_box != (Object)null)
					{
						PileBag.DumpInto(localPlayer, _box);
					}
				};
				<>c.<>9__20_1 = val3;
				obj4 = (object)val3;
			}
			Button("stack", "Stack", pos2, (UnityAction)obj4);
		}

		private static void Button(string name, string title, Vector2 pos, UnityAction click)
		{
			//IL_002b: 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)
			//IL_004a: 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_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: 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)
			GameObject val = RestlessUi.Chip(_tray.transform, name);
			RestlessUi.PaperControl(val, (Color?)null);
			RestlessUi.Pin(val, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), pos, new Vector2(148f, 36f));
			RestlessUi.Stretch(((Component)RestlessUi.Label(val.transform, title, 15, RestlessUi.Text, (TextAnchor)4)).gameObject, Vector2.zero, Vector2.one, new Vector2(8f, 0f), new Vector2(-8f, 0f));
			Button obj = val.AddComponent<Button>();
			((Selectable)obj).targetGraphic = (Graphic)(object)val.GetComponent<Image>();
			RestlessUi.PaperSelectable((Selectable)(object)obj);
			((UnityEvent)obj.onClick).AddListener(click);
		}

		private static void Refresh()
		{
			if ((Object)(object)_box == (Object)null || (Object)(object)_tray == (Object)null)
			{
				return;
			}
			if (!((Behaviour)_box).isActiveAndEnabled)
			{
				Close();
				return;
			}
			if ((Object)(object)_title != (Object)null)
			{
				_title.text = _box.GetHoverName();
			}
			if ((Object)(object)_title != (Object)null)
			{
				RestlessUi.TitleTear(_tray, ((Graphic)_title).rectTransform);
			}
			if ((Object)(object)_meta != (Object)null)
			{
				_meta.text = _box.Stored.ToString();
			}
			if ((Object)(object)_icon != (Object)null)
			{
				_icon.sprite = RestlessUi.IconOf(_box.Item);
				((Behaviour)_icon).enabled = (Object)(object)_icon.sprite != (Object)null;
			}
			if ((Object)(object)_slot != (Object)null && _box.Item != null)
			{
				ItemData val = _box.Item.Clone();
				val.m_stack = 1;
				RestlessUi.DressSlot(_slot, _icon, false, val, (List<Behaviour>)null, false, false, false);
			}
		}
	}
	[BepInPlugin("restless.piles", "RestlessPiles", "0.1.6")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "restless.piles";

		public const string PluginName = "RestlessPiles";

		public const string PluginVersion = "0.1.6";

		private Harmony? _harmony;

		private IDisposable? _settings;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			PileConfig.Bind(((BaseUnityPlugin)this).Config);
			_settings = PileSettings.Register();
			_harmony = new Harmony("restless.piles");
			_harmony.PatchAll();
			GUIManager.OnCustomGUIAvailable += PileUi.TearDown;
			Log.LogInfo((object)"RestlessPiles 0.1.6 loaded.");
		}

		private void Update()
		{
			if (!Console.IsVisible())
			{
				PileUi.Tick();
			}
		}

		private void OnDestroy()
		{
			_settings?.Dispose();
			GUIManager.OnCustomGUIAvailable -= PileUi.TearDown;
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}