Decompiled source of Build From Chest v0.2.0

FrizzQOL.BuildFromChest.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("FrizzQOL.BuildFromChest")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+35261d2f7e3d995926cc3286547d09a3bb9d958e")]
[assembly: AssemblyProduct("FrizzQOL.BuildFromChest")]
[assembly: AssemblyTitle("FrizzQOL.BuildFromChest")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BuildFromChest
{
	public sealed class ItemAmount
	{
		public string SharedName;

		public string PrefabName;

		public int Amount;
	}
	public sealed class PlannedTake
	{
		public int ChestId;

		public string SharedName;

		public string PrefabName;

		public int Amount;
	}
	public sealed class ChestCandidate
	{
		public int Id;

		public float Distance;

		public bool CanOpen;

		public Dictionary<string, int> Counts;
	}
	public static class ChestPay
	{
		public static int Missing(int cost, int inInventory)
		{
			int num = cost - inInventory;
			if (num <= 0)
			{
				return 0;
			}
			return num;
		}

		public static void AddCost(IList<ItemAmount> costs, string sharedName, string prefabName, int amount)
		{
			if (costs == null || amount <= 0 || string.IsNullOrEmpty(sharedName) || string.IsNullOrEmpty(prefabName))
			{
				return;
			}
			for (int i = 0; i < costs.Count; i++)
			{
				ItemAmount itemAmount = costs[i];
				if (itemAmount != null && itemAmount.SharedName == sharedName)
				{
					itemAmount.Amount += amount;
					return;
				}
			}
			costs.Add(new ItemAmount
			{
				SharedName = sharedName,
				PrefabName = prefabName,
				Amount = amount
			});
		}

		public static List<ItemAmount> MissingItems(IList<ItemAmount> costs, IDictionary<string, int> have)
		{
			List<ItemAmount> list = new List<ItemAmount>();
			if (costs == null)
			{
				return list;
			}
			for (int i = 0; i < costs.Count; i++)
			{
				ItemAmount itemAmount = costs[i];
				if (itemAmount != null && itemAmount.Amount > 0 && !string.IsNullOrEmpty(itemAmount.SharedName) && !string.IsNullOrEmpty(itemAmount.PrefabName))
				{
					int value = 0;
					have?.TryGetValue(itemAmount.SharedName, out value);
					int num = Missing(itemAmount.Amount, value);
					if (num > 0)
					{
						list.Add(new ItemAmount
						{
							SharedName = itemAmount.SharedName,
							PrefabName = itemAmount.PrefabName,
							Amount = num
						});
					}
				}
			}
			return list;
		}

		public static bool NeedsPull(IList<ItemAmount> missing)
		{
			if (missing == null)
			{
				return false;
			}
			for (int i = 0; i < missing.Count; i++)
			{
				ItemAmount itemAmount = missing[i];
				if (itemAmount != null && itemAmount.Amount > 0 && !string.IsNullOrEmpty(itemAmount.SharedName) && !string.IsNullOrEmpty(itemAmount.PrefabName))
				{
					return true;
				}
			}
			return false;
		}

		public static List<PlannedTake> PlanPulls(IList<ChestCandidate> chests, IList<ItemAmount> missing, float radius)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			Dictionary<string, string> dictionary2 = new Dictionary<string, string>();
			if (missing != null)
			{
				for (int i = 0; i < missing.Count; i++)
				{
					ItemAmount itemAmount = missing[i];
					if (itemAmount != null && itemAmount.Amount > 0 && !string.IsNullOrEmpty(itemAmount.SharedName) && !string.IsNullOrEmpty(itemAmount.PrefabName))
					{
						if (dictionary.ContainsKey(itemAmount.SharedName))
						{
							dictionary[itemAmount.SharedName] += itemAmount.Amount;
							continue;
						}
						dictionary[itemAmount.SharedName] = itemAmount.Amount;
						dictionary2[itemAmount.SharedName] = itemAmount.PrefabName;
					}
				}
			}
			if (dictionary.Count == 0)
			{
				return new List<PlannedTake>();
			}
			if (chests == null)
			{
				return null;
			}
			List<ChestCandidate> list = new List<ChestCandidate>();
			for (int j = 0; j < chests.Count; j++)
			{
				ChestCandidate chestCandidate = chests[j];
				if (chestCandidate != null && chestCandidate.CanOpen && IsInRange(chestCandidate.Distance, radius))
				{
					list.Add(chestCandidate);
				}
			}
			list.Sort(CompareChests);
			List<PlannedTake> list2 = new List<PlannedTake>();
			for (int k = 0; k < list.Count; k++)
			{
				ChestCandidate chestCandidate2 = list[k];
				foreach (string item in new List<string>(dictionary.Keys))
				{
					int num = dictionary[item];
					if (num > 0)
					{
						int value = 0;
						if (chestCandidate2.Counts != null)
						{
							chestCandidate2.Counts.TryGetValue(item, out value);
						}
						int num2 = ((value < num) ? value : num);
						if (num2 > 0)
						{
							list2.Add(new PlannedTake
							{
								ChestId = chestCandidate2.Id,
								SharedName = item,
								PrefabName = dictionary2[item],
								Amount = num2
							});
							dictionary[item] = num - num2;
						}
					}
				}
			}
			foreach (int value2 in dictionary.Values)
			{
				if (value2 > 0)
				{
					return null;
				}
			}
			return list2;
		}

		public static bool IsInRange(float distance, float radius)
		{
			if (radius > 0f)
			{
				return distance <= radius;
			}
			return false;
		}

		public static bool IsChestPrefab(string name)
		{
			switch (name)
			{
			default:
				return name == "piece_chest_blackmetal";
			case "piece_chest_wood":
			case "piece_chest":
			case "piece_chest_private":
				return true;
			}
		}

		public static bool IsHammer(string prefabName)
		{
			return prefabName == "Hammer";
		}

		public static string PrefabKey(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "";
			}
			if (name.EndsWith("(Clone)"))
			{
				return name.Substring(0, name.Length - "(Clone)".Length);
			}
			return name;
		}

		public static int? PickNearest(IList<ChestCandidate> candidates, float radius)
		{
			int? result = null;
			float num = 0f;
			if (candidates == null)
			{
				return null;
			}
			for (int i = 0; i < candidates.Count; i++)
			{
				ChestCandidate chestCandidate = candidates[i];
				if (chestCandidate != null && chestCandidate.CanOpen && IsInRange(chestCandidate.Distance, radius) && (!result.HasValue || chestCandidate.Distance < num || (chestCandidate.Distance == num && chestCandidate.Id < result.Value)))
				{
					result = chestCandidate.Id;
					num = chestCandidate.Distance;
				}
			}
			return result;
		}

		private static int CompareChests(ChestCandidate a, ChestCandidate b)
		{
			int num = a.Distance.CompareTo(b.Distance);
			if (num != 0)
			{
				return num;
			}
			return a.Id.CompareTo(b.Id);
		}
	}
	[HarmonyPatch(typeof(Player), "TryPlacePiece")]
	internal static class PlacePatch
	{
		private sealed class HeldTake
		{
			public Container Chest;

			public readonly List<MovedStack> Items = new List<MovedStack>();
		}

		private sealed class MovedStack
		{
			public string SharedName;

			public string PrefabName;

			public int TakenFromChest;

			public int GivenToPlayer;
		}

		private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", (Type[])null, (Type[])null);

		private static readonly MethodInfo LoadMethod = AccessTools.Method(typeof(Container), "Load", Type.EmptyTypes, (Type[])null);

		private static readonly MethodInfo SaveMethod = AccessTools.Method(typeof(Container), "Save", (Type[])null, (Type[])null);

		private static readonly FieldInfo NViewField = AccessTools.Field(typeof(Container), "m_nview");

		private static bool _busy;

		private static bool _loggedAccess;

		private static bool _loggedSave;

		private static readonly List<HeldTake> Held = new List<HeldTake>();

		private static void Prefix(Player __instance, Piece piece)
		{
			if (!_busy && Held.Count <= 0)
			{
				Prepare(__instance, piece);
			}
		}

		internal static void Prepare(Player player, Piece piece)
		{
			if (_busy || Held.Count > 0 || (Object)(object)player == (Object)null || (Object)(object)piece == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !CanSaveChests())
			{
				return;
			}
			ItemData rightItem = ((Humanoid)player).RightItem;
			if (!ChestPay.IsHammer((rightItem != null && (Object)(object)rightItem.m_dropPrefab != (Object)null) ? ChestPay.PrefabKey(((Object)rightItem.m_dropPrefab).name) : "") || IsFreeBuild(piece))
			{
				return;
			}
			List<ItemAmount> costs = new List<ItemAmount>();
			SumCosts(piece.m_resources, costs);
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<ItemAmount> missing = ChestPay.MissingItems(costs, CountHave(inventory, costs));
			if (!ChestPay.NeedsPull(missing))
			{
				return;
			}
			float radius = Plugin.CurrentRadius();
			List<ChestCandidate> chests = new List<ChestCandidate>();
			Dictionary<int, Container> dictionary = new Dictionary<int, Container>();
			FindChests(player, radius, missing, chests, dictionary);
			List<PlannedTake> list = ChestPay.PlanPulls(chests, missing, radius);
			if (list == null || list.Count == 0)
			{
				return;
			}
			_busy = true;
			try
			{
				ApplyPlan(inventory, list, dictionary);
			}
			catch (Exception ex)
			{
				ReturnHeld(player);
				Plugin.LogWarning("Chest pull failed: " + ex.Message);
			}
			finally
			{
				_busy = false;
				dictionary.Clear();
			}
		}

		internal static void Finish(Player player)
		{
			ReturnHeld(player);
		}

		private static bool IsFreeBuild(Piece piece)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)piece == (Object)null || (Object)(object)instance == (Object)null)
			{
				return false;
			}
			return instance.GetGlobalKey(piece.FreeBuildKey());
		}

		private static void Postfix(Player __instance, bool __result)
		{
			try
			{
				if (__result)
				{
					Held.Clear();
				}
				else
				{
					ReturnHeld(__instance);
				}
			}
			finally
			{
				_busy = false;
			}
		}

		private static void SumCosts(Requirement[] requirements, List<ItemAmount> costs)
		{
			if (requirements == null)
			{
				return;
			}
			foreach (Requirement val in requirements)
			{
				if (val != null && !((Object)(object)val.m_resItem == (Object)null) && val.m_resItem.m_itemData != null && val.m_resItem.m_itemData.m_shared != null && val.m_amount > 0 && !((Object)(object)((Component)val.m_resItem).gameObject == (Object)null))
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					string prefabName = ChestPay.PrefabKey(((Object)((Component)val.m_resItem).gameObject).name);
					ChestPay.AddCost(costs, name, prefabName, val.m_amount);
				}
			}
		}

		private static Dictionary<string, int> CountHave(Inventory inventory, List<ItemAmount> costs)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			for (int i = 0; i < costs.Count; i++)
			{
				string sharedName = costs[i].SharedName;
				if (!dictionary.ContainsKey(sharedName))
				{
					dictionary[sharedName] = inventory.CountItems(sharedName, -1, true);
				}
			}
			return dictionary;
		}

		private static void FindChests(Player player, float radius, List<ItemAmount> missing, List<ChestCandidate> chests, Dictionary<int, Container> byId)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			if (radius <= 0f)
			{
				return;
			}
			Vector3 position = ((Component)player).transform.position;
			Collider[] array = Physics.OverlapSphere(position, radius + 2f, -1, (QueryTriggerInteraction)2);
			for (int i = 0; i < array.Length; i++)
			{
				Collider val = array[i];
				array[i] = null;
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Container componentInParent = ((Component)val).GetComponentInParent<Container>();
				if ((Object)(object)componentInParent == (Object)null)
				{
					continue;
				}
				int instanceID = ((Object)componentInParent).GetInstanceID();
				if (byId.ContainsKey(instanceID) || !ChestPay.IsChestPrefab(ChestPay.PrefabKey(((Object)((Component)componentInParent).gameObject).name)))
				{
					continue;
				}
				bool flag = CanOpen(componentInParent, player);
				Inventory val2 = (flag ? componentInParent.GetInventory() : null);
				if (flag && val2 != null)
				{
					RefreshChest(componentInParent);
					val2 = componentInParent.GetInventory();
				}
				Dictionary<string, int> dictionary = new Dictionary<string, int>();
				if (val2 != null)
				{
					for (int j = 0; j < missing.Count; j++)
					{
						string sharedName = missing[j].SharedName;
						if (!dictionary.ContainsKey(sharedName))
						{
							dictionary[sharedName] = val2.CountItems(sharedName, -1, true);
						}
					}
				}
				chests.Add(new ChestCandidate
				{
					Id = instanceID,
					Distance = Vector3.Distance(position, ((Component)componentInParent).transform.position),
					CanOpen = (flag && val2 != null),
					Counts = dictionary
				});
				byId[instanceID] = componentInParent;
			}
		}

		private static void ApplyPlan(Inventory playerInventory, List<PlannedTake> plan, Dictionary<int, Container> chests)
		{
			List<HeldTake> list = new List<HeldTake>();
			HeldTake heldTake = null;
			int num = 0;
			try
			{
				for (int i = 0; i < plan.Count; i++)
				{
					PlannedTake plannedTake = plan[i];
					if (plannedTake == null || plannedTake.Amount <= 0)
					{
						continue;
					}
					if (heldTake == null || plannedTake.ChestId != num)
					{
						if (heldTake != null)
						{
							SaveChest(heldTake.Chest);
							list.Add(heldTake);
						}
						if (!chests.TryGetValue(plannedTake.ChestId, out var value) || (Object)(object)value == (Object)null || value.GetInventory() == null)
						{
							UndoMoved(playerInventory, list);
							return;
						}
						heldTake = new HeldTake
						{
							Chest = value
						};
						num = plannedTake.ChestId;
					}
					int num2 = Take(heldTake.Chest.GetInventory(), plannedTake.SharedName, plannedTake.Amount);
					int num3 = ((num2 == plannedTake.Amount) ? Give(playerInventory, plannedTake.PrefabName, plannedTake.SharedName, plannedTake.Amount) : 0);
					heldTake.Items.Add(new MovedStack
					{
						SharedName = plannedTake.SharedName,
						PrefabName = plannedTake.PrefabName,
						TakenFromChest = num2,
						GivenToPlayer = num3
					});
					if (num2 != plannedTake.Amount || num3 != plannedTake.Amount)
					{
						SaveChest(heldTake.Chest);
						list.Add(heldTake);
						heldTake = null;
						UndoMoved(playerInventory, list);
						return;
					}
				}
				if (heldTake != null)
				{
					SaveChest(heldTake.Chest);
					list.Add(heldTake);
				}
				Held.AddRange(list);
			}
			catch (Exception ex)
			{
				if (heldTake != null && !list.Contains(heldTake))
				{
					list.Add(heldTake);
				}
				UndoMoved(playerInventory, list);
				Held.Clear();
				Plugin.LogWarning("Chest pull failed, restoring items: " + ex.Message);
			}
		}

		private static void ReturnHeld(Player player)
		{
			if (Held.Count == 0)
			{
				_busy = false;
				return;
			}
			List<HeldTake> moved = new List<HeldTake>(Held);
			Held.Clear();
			_busy = false;
			if ((Object)(object)player == (Object)null || ((Humanoid)player).GetInventory() == null)
			{
				Plugin.LogWarning("Could not return pulled materials.");
			}
			else
			{
				UndoMoved(((Humanoid)player).GetInventory(), moved);
			}
		}

		private static void UndoMoved(Inventory playerInventory, List<HeldTake> moved)
		{
			for (int i = 0; i < moved.Count; i++)
			{
				HeldTake heldTake = moved[i];
				if (heldTake == null || (Object)(object)heldTake.Chest == (Object)null || heldTake.Chest.GetInventory() == null || playerInventory == null)
				{
					Plugin.LogWarning("Could not return pulled materials.");
					continue;
				}
				Inventory inventory = heldTake.Chest.GetInventory();
				for (int j = 0; j < heldTake.Items.Count; j++)
				{
					MovedStack movedStack = heldTake.Items[j];
					int num = Take(playerInventory, movedStack.SharedName, movedStack.GivenToPlayer);
					int num2 = movedStack.TakenFromChest - movedStack.GivenToPlayer + num;
					int num3 = Give(inventory, movedStack.PrefabName, movedStack.SharedName, num2);
					int num4 = num2 - num3;
					if (num4 > 0)
					{
						Give(playerInventory, movedStack.PrefabName, movedStack.SharedName, num4);
					}
					if (num != movedStack.GivenToPlayer || num4 > 0)
					{
						Plugin.LogWarning("Pulled materials could not all return to the chest.");
					}
				}
				SaveChest(heldTake.Chest);
			}
		}

		private static bool CanOpen(Container container, Player player)
		{
			if (CheckAccessMethod == null)
			{
				if (!_loggedAccess)
				{
					_loggedAccess = true;
					Plugin.LogWarning("Container.CheckAccess is missing. Chest pull is off.");
				}
				return false;
			}
			object obj = CheckAccessMethod.Invoke(container, new object[1] { player.GetPlayerID() });
			if (!(obj is bool) || !(bool)obj || container.IsInUse())
			{
				return false;
			}
			if (NViewField == null)
			{
				return false;
			}
			object? value = NViewField.GetValue(container);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			if (val == null || (Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return false;
			}
			return true;
		}

		private static bool CanSaveChests()
		{
			if (SaveMethod != null)
			{
				return true;
			}
			if (!_loggedSave)
			{
				_loggedSave = true;
				Plugin.LogWarning("Container.Save is missing. Chest pull is off.");
			}
			return false;
		}

		private static void RefreshChest(Container container)
		{
			if ((Object)(object)container != (Object)null && LoadMethod != null)
			{
				LoadMethod.Invoke(container, null);
			}
		}

		private static void SaveChest(Container container)
		{
			if ((Object)(object)container != (Object)null && SaveMethod != null)
			{
				SaveMethod.Invoke(container, null);
			}
		}

		private static int Take(Inventory inventory, string sharedName, int amount)
		{
			if (inventory == null || amount <= 0 || string.IsNullOrEmpty(sharedName))
			{
				return 0;
			}
			int num = inventory.CountItems(sharedName, -1, true);
			inventory.RemoveItem(sharedName, amount, -1, true);
			return num - inventory.CountItems(sharedName, -1, true);
		}

		private static int Give(Inventory inventory, string prefabName, string sharedName, int amount)
		{
			if (inventory == null || amount <= 0 || string.IsNullOrEmpty(prefabName) || string.IsNullOrEmpty(sharedName))
			{
				return 0;
			}
			int num = inventory.CountItems(sharedName, -1, true);
			inventory.AddItem(prefabName, amount, 1, 0, 0L, "", false, false);
			return inventory.CountItems(sharedName, -1, true) - num;
		}
	}
	public static class PlacementClick
	{
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class UpdatePlacementPatch
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0099: Expected O, but got Unknown
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Expected O, but got Unknown
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Expected O, but got Unknown
				List<CodeInstruction> list = new List<CodeInstruction>(instructions);
				MethodInfo methodInfo = AccessTools.Method(typeof(PlacementClick), "PullBeforeRequirements", (Type[])null, (Type[])null);
				for (int i = 3; i < list.Count; i++)
				{
					if (IsPieceRequirementCheck(list[i]))
					{
						CodeInstruction val = list[i - 2];
						if (!(list[i - 3].opcode != OpCodes.Ldarg_0) && IsLoadLocal(val.opcode) && !(list[i - 1].opcode != OpCodes.Ldc_I4_0))
						{
							int num = i - 3;
							list.Insert(num, new CodeInstruction(OpCodes.Ldarg_0, (object)null));
							list.Insert(num + 1, new CodeInstruction(val.opcode, val.operand));
							list.Insert(num + 2, new CodeInstruction(OpCodes.Call, (object)methodInfo));
							return list;
						}
					}
				}
				Plugin.LogWarning("UpdatePlacement does not check requirements before place. A short hammer click will not pull.");
				return list;
			}

			private static void Postfix(Player __instance)
			{
				PlacePatch.Finish(__instance);
			}

			private static Exception Finalizer(Player __instance, Exception __exception)
			{
				PlacePatch.Finish(__instance);
				return __exception;
			}

			private static bool IsPieceRequirementCheck(CodeInstruction instruction)
			{
				if (instruction.opcode != OpCodes.Call && instruction.opcode != OpCodes.Callvirt)
				{
					return false;
				}
				MethodInfo methodInfo = instruction.operand as MethodInfo;
				if (methodInfo == null || methodInfo.Name != "HaveRequirements")
				{
					return false;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 2)
				{
					return parameters[0].ParameterType == typeof(Piece);
				}
				return false;
			}

			private static bool IsLoadLocal(OpCode opcode)
			{
				if (!(opcode == OpCodes.Ldloc) && !(opcode == OpCodes.Ldloc_S) && !(opcode == OpCodes.Ldloc_0) && !(opcode == OpCodes.Ldloc_1) && !(opcode == OpCodes.Ldloc_2))
				{
					return opcode == OpCodes.Ldloc_3;
				}
				return true;
			}
		}

		public static void PullBeforeRequirements(Player player, Piece piece)
		{
			PlacePatch.Prepare(player, piece);
		}
	}
	[BepInPlugin("com.frizzqol.buildfromchest", "FrizzQOL Build From Chest", "0.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.frizzqol.buildfromchest";

		public const string PluginName = "FrizzQOL Build From Chest";

		public const string PluginVersion = "0.2.0";

		internal static ConfigEntry<float> ChestRadius;

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			Instance = this;
			ChestRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ChestRadius", 10f, "Meters from the player to the nearest chest. 0 or less disables the pull.");
			_harmony = new Harmony("com.frizzqol.buildfromchest");
			try
			{
				_harmony.PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"FrizzQOL Build From Chest 0.2.0 loaded");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch placement: " + ex.Message));
			}
		}

		internal static float CurrentRadius()
		{
			if (ChestRadius == null)
			{
				return 10f;
			}
			return ChestRadius.Value;
		}

		internal static void LogWarning(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
			}
		}
	}
}