Decompiled source of CraftFromChestOptimized v1.0.0

despr0grammer.CraftFromChestOptimized.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[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 despr0grammer.CraftFromChestOptimized
{
	internal static class ChestRegistry
	{
		private sealed class Entry
		{
			internal int Id;

			internal Container Container;

			internal Transform Transform;

			internal Transform Root;

			internal ZNetView NetView;

			internal Collider[] Colliders;
		}

		private struct Candidate
		{
			internal Container Container;

			internal float SqrDistance;
		}

		internal const float Radius = 20f;

		private static readonly List<Entry> Entries = new List<Entry>(64);

		private static readonly HashSet<int> Known = new HashSet<int>();

		private static readonly List<Candidate> Scratch = new List<Candidate>(32);

		private static readonly Comparison<Candidate> ByDistance = (Candidate a, Candidate b) => a.SqrDistance.CompareTo(b.SqrDistance);

		private static int _pieceLayer = -2;

		private static int PieceLayer
		{
			get
			{
				if (_pieceLayer == -2)
				{
					_pieceLayer = LayerMask.NameToLayer("piece");
				}
				return _pieceLayer;
			}
		}

		internal static void Register(Container container)
		{
			if (!((Object)(object)container == (Object)null) && Known.Add(((Object)container).GetInstanceID()))
			{
				Entries.Add(Build(container));
			}
		}

		internal static void SeedFromScene()
		{
			Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				Register(array[i]);
			}
		}

		internal static void Prune()
		{
			for (int num = Entries.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Entries[num].Container == (Object)null)
				{
					RemoveAt(num);
				}
			}
		}

		internal static void Find(Vector3 center, long playerId, List<Container> result)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: 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)
			result.Clear();
			Scratch.Clear();
			float num = 400f;
			for (int num2 = Entries.Count - 1; num2 >= 0; num2--)
			{
				Entry entry = Entries[num2];
				if ((Object)(object)entry.Container == (Object)null)
				{
					RemoveAt(num2);
					continue;
				}
				Vector3 val = entry.Transform.position - center;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude > num)
				{
					val = entry.Root.position - center;
					if (((Vector3)(ref val)).sqrMagnitude > num)
					{
						continue;
					}
				}
				if (IsUsable(entry, playerId))
				{
					Scratch.Add(new Candidate
					{
						Container = entry.Container,
						SqrDistance = sqrMagnitude
					});
				}
			}
			Scratch.Sort(ByDistance);
			for (int i = 0; i < Scratch.Count; i++)
			{
				result.Add(Scratch[i].Container);
			}
		}

		private static bool IsUsable(Entry entry, long playerId)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)entry.NetView == (Object)null || !entry.NetView.IsValid())
			{
				return false;
			}
			Container container = entry.Container;
			if (container.GetInventory() == null)
			{
				return false;
			}
			if (!HasLiveCollider(entry))
			{
				return false;
			}
			if (!GameAccess.CheckAccess(container, playerId))
			{
				return false;
			}
			if (container.m_checkGuardStone)
			{
				return PrivateArea.CheckAccess(entry.Transform.position, 0f, false, false);
			}
			return true;
		}

		private static bool HasLiveCollider(Entry entry)
		{
			Collider[] colliders = entry.Colliders;
			foreach (Collider val in colliders)
			{
				if ((Object)(object)val != (Object)null && val.enabled && ((Component)val).gameObject.activeInHierarchy)
				{
					return true;
				}
			}
			return false;
		}

		private static void RemoveAt(int index)
		{
			Known.Remove(Entries[index].Id);
			int index2 = Entries.Count - 1;
			Entries[index] = Entries[index2];
			Entries.RemoveAt(index2);
		}

		private static Entry Build(Container container)
		{
			ZNetView val = ((Component)container).GetComponent<ZNetView>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)container).GetComponentInParent<ZNetView>();
			}
			List<Collider> list = new List<Collider>();
			int pieceLayer = PieceLayer;
			CollectResolved(container, ((Component)container).GetComponentsInChildren<Collider>(true), pieceLayer, list);
			Transform parent = ((Component)container).transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				CollectResolved(container, ((Component)parent).GetComponents<Collider>(), pieceLayer, list);
				parent = parent.parent;
			}
			Incinerator componentInParent = ((Component)container).GetComponentInParent<Incinerator>();
			if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent.m_container == (Object)(object)container)
			{
				Collider[] componentsInChildren = ((Component)componentInParent).GetComponentsInChildren<Collider>(true);
				foreach (Collider val2 in componentsInChildren)
				{
					if (((Component)val2).gameObject.layer == pieceLayer && !list.Contains(val2))
					{
						list.Add(val2);
					}
				}
			}
			return new Entry
			{
				Id = ((Object)container).GetInstanceID(),
				Container = container,
				Transform = ((Component)container).transform,
				Root = ((Component)container).transform.root,
				NetView = val,
				Colliders = list.ToArray()
			};
		}

		private static void CollectResolved(Container owner, Collider[] candidates, int layer, List<Collider> into)
		{
			foreach (Collider val in candidates)
			{
				if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.layer == layer && !into.Contains(val))
				{
					Container val2 = ((Component)val).GetComponentInParent<Container>();
					if ((Object)(object)val2 == (Object)null)
					{
						val2 = ((Component)val).GetComponentInChildren<Container>();
					}
					if ((Object)(object)val2 == (Object)(object)owner)
					{
						into.Add(val);
					}
				}
			}
		}
	}
	internal static class ChestScope
	{
		private readonly struct CountKey : IEquatable<CountKey>
		{
			private readonly string _name;

			private readonly int _quality;

			internal CountKey(string name, int quality)
			{
				_name = name;
				_quality = quality;
			}

			public bool Equals(CountKey other)
			{
				if (_quality == other._quality)
				{
					return _name == other._name;
				}
				return false;
			}

			public override bool Equals(object obj)
			{
				if (obj is CountKey other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return (_name.GetHashCode() * 397) ^ _quality;
			}
		}

		private static int _depth;

		private static bool _bypass;

		private static Player _player;

		private static Inventory _playerInventory;

		private static readonly List<Container> Chests = new List<Container>(32);

		private static readonly List<Container> NoChests = new List<Container>(0);

		private static int _chestsFrame = -1;

		private static readonly Dictionary<CountKey, int> Counts = new Dictionary<CountKey, int>();

		private static int _countsFrame = -1;

		private static int _countsVersion;

		private static int _version;

		internal static bool Enabled { get; private set; } = true;

		internal static bool Active
		{
			get
			{
				if (_depth > 0)
				{
					return !_bypass;
				}
				return false;
			}
		}

		internal static void SetEnabled(bool enabled)
		{
			Enabled = enabled;
			_chestsFrame = -1;
			_countsFrame = -1;
			Chests.Clear();
			Counts.Clear();
		}

		internal static bool Enter(Player player)
		{
			if (!Enabled || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (_depth == 0)
			{
				_player = player;
				_playerInventory = ((Humanoid)player).GetInventory();
			}
			_depth++;
			return true;
		}

		internal static void Exit(bool entered)
		{
			if (entered && _depth > 0)
			{
				_depth--;
				if (_depth == 0)
				{
					_player = null;
					_playerInventory = null;
				}
			}
		}

		internal static void EndFrameCheck()
		{
			if (_depth != 0 || _bypass)
			{
				Plugin.Log.LogWarning((object)"Craft scope was left open; resetting it.");
				_depth = 0;
				_bypass = false;
				_player = null;
				_playerInventory = null;
			}
		}

		internal static int CountInChests(string name, int quality = -1)
		{
			List<Container> list = NearbyChests();
			if (list.Count == 0)
			{
				return 0;
			}
			if (name == null)
			{
				return Sum(list, null, quality);
			}
			int frameCount = Time.frameCount;
			if (_countsFrame != frameCount || _countsVersion != _version)
			{
				Counts.Clear();
				_countsFrame = frameCount;
				_countsVersion = _version;
			}
			CountKey key = new CountKey(name, quality);
			if (!Counts.TryGetValue(key, out var value))
			{
				value = Sum(list, name, quality);
				Counts[key] = value;
			}
			return value;
		}

		internal static void AddChestCount(Inventory inventory, string name, int quality, ref int result)
		{
			if (Active && inventory == _playerInventory)
			{
				result += CountInChests(name, quality);
			}
		}

		internal static bool TryRemoveFromChests(Inventory inventory, string name, int amount, int itemQuality, bool worldLevelBased)
		{
			if (!Active || inventory == null || inventory != _playerInventory || amount <= 0)
			{
				return false;
			}
			_bypass = true;
			try
			{
				int num = Mathf.Min(inventory.CountItems(name, itemQuality, worldLevelBased), amount);
				if (num > 0)
				{
					inventory.RemoveItem(name, num, itemQuality, worldLevelBased);
				}
				int num2 = amount - num;
				if (num2 > 0)
				{
					TakeFromChests(name, num2, itemQuality);
				}
			}
			finally
			{
				_bypass = false;
				_version++;
			}
			return true;
		}

		private static List<Container> NearbyChests()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Player player = _player;
			if ((Object)(object)player == (Object)null)
			{
				return NoChests;
			}
			int frameCount = Time.frameCount;
			if (_chestsFrame != frameCount)
			{
				_chestsFrame = frameCount;
				ChestRegistry.Find(((Component)player).transform.position, player.GetPlayerID(), Chests);
			}
			return Chests;
		}

		private static int Sum(List<Container> chests, string name, int quality)
		{
			int num = 0;
			for (int i = 0; i < chests.Count; i++)
			{
				Inventory inventory = chests[i].GetInventory();
				if (inventory != null)
				{
					num += inventory.CountItems(name, quality, true);
				}
			}
			return num;
		}

		private static void TakeFromChests(string name, int amount, int quality)
		{
			List<Container> list = NearbyChests();
			int num = amount;
			for (int i = 0; i < list.Count; i++)
			{
				if (num <= 0)
				{
					break;
				}
				Container val = list[i];
				Inventory inventory = val.GetInventory();
				if (inventory != null)
				{
					int num2 = inventory.CountItems(name, quality, true);
					if (num2 > 0)
					{
						int num3 = Mathf.Min(num2, num);
						inventory.RemoveItem(name, num3, quality, true);
						GameAccess.Save(val);
						num -= num3;
					}
				}
			}
		}
	}
	internal static class GameAccess
	{
		private static readonly Func<Container, long, bool> CheckAccessImpl = Bind<Func<Container, long, bool>>(typeof(Container), "CheckAccess", new Type[1] { typeof(long) });

		private static readonly Action<Container> SaveImpl = Bind<Action<Container>>(typeof(Container), "Save", Array.Empty<Type>());

		private static readonly Action<InventoryGui, bool> UpdateCraftingPanelImpl = Bind<Action<InventoryGui, bool>>(typeof(InventoryGui), "UpdateCraftingPanel", new Type[1] { typeof(bool) });

		internal static bool Ready
		{
			get
			{
				if (CheckAccessImpl != null)
				{
					return SaveImpl != null;
				}
				return false;
			}
		}

		internal static bool CheckAccess(Container container, long playerId)
		{
			if (CheckAccessImpl == null)
			{
				return false;
			}
			try
			{
				return CheckAccessImpl(container, playerId);
			}
			catch (Exception)
			{
				return false;
			}
		}

		internal static void Save(Container container)
		{
			SaveImpl?.Invoke(container);
		}

		internal static void RefreshCraftingPanel(InventoryGui gui)
		{
			if ((Object)(object)gui == (Object)null || UpdateCraftingPanelImpl == null)
			{
				return;
			}
			try
			{
				UpdateCraftingPanelImpl(gui, arg2: false);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not refresh the crafting panel: " + ex.Message));
			}
		}

		private static T Bind<T>(Type owner, string name, params Type[] args) where T : class
		{
			MethodInfo methodInfo = AccessTools.Method(owner, name, args, (Type[])null);
			if (!(methodInfo == null))
			{
				return (T)(object)Delegate.CreateDelegate(typeof(T), methodInfo);
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Container), "Awake")]
	internal static class ContainerAwakePatch
	{
		private static bool _reported;

		private static void Postfix(Container __instance)
		{
			try
			{
				ChestRegistry.Register(__instance);
			}
			catch (Exception arg)
			{
				if (!_reported)
				{
					_reported = true;
					Plugin.Log.LogError((object)$"Could not register a container: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirementItems")]
	internal static class HaveRequirementItemsPatch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = ChestScope.Enter(__instance);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Piece),
		typeof(RequirementMode)
	})]
	internal static class HaveRequirementsPiecePatch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = ChestScope.Enter(__instance);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
	{
		typeof(Recipe),
		typeof(bool),
		typeof(int),
		typeof(int)
	})]
	internal static class HaveRequirementsRecipePatch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = ChestScope.Enter(__instance);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeResources")]
	internal static class ConsumeResourcesPatch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = ChestScope.Enter(__instance);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(Player), "GetFirstRequiredItem")]
	internal static class GetFirstRequiredItemPatch
	{
		private static void Prefix(Player __instance, out bool __state)
		{
			__state = ChestScope.Enter(__instance);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "DoCrafting")]
	internal static class DoCraftingPatch
	{
		private static void Prefix(Player player, out bool __state)
		{
			__state = ChestScope.Enter(player);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	internal static class SetupRequirementPatch
	{
		private static void Prefix(Player player, out bool __state)
		{
			__state = ChestScope.Enter(player);
		}

		private static void Finalizer(bool __state)
		{
			ChestScope.Exit(__state);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
	internal static class RequirementLabelPatch
	{
		private const int MaxCachedLabels = 1024;

		private static readonly Dictionary<long, string> Labels = new Dictionary<long, string>();

		private static bool _reported;

		private static void Postfix(Transform elementRoot, Requirement req, int quality, int craftMultiplier)
		{
			if (!ChestScope.Active)
			{
				return;
			}
			try
			{
				AppendChestAvailability(elementRoot, req, quality, craftMultiplier);
			}
			catch (Exception arg)
			{
				if (!_reported)
				{
					_reported = true;
					Plugin.Log.LogError((object)$"Could not update a requirement label: {arg}");
				}
			}
		}

		private static void AppendChestAvailability(Transform elementRoot, Requirement req, int quality, int craftMultiplier)
		{
			string text = req?.m_resItem?.m_itemData?.m_shared?.m_name;
			if (string.IsNullOrEmpty(text) || (Object)(object)elementRoot == (Object)null)
			{
				return;
			}
			int num = req.GetAmount(quality) * craftMultiplier;
			if (num > 0)
			{
				Transform val = elementRoot.Find("res_amount");
				TMP_Text val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : null);
				if (!((Object)(object)val2 == (Object)null))
				{
					val2.text = Label(num, ChestScope.CountInChests(text));
				}
			}
		}

		private static string Label(int need, int inChests)
		{
			long key = ((long)need << 32) | (uint)inChests;
			if (!Labels.TryGetValue(key, out var value))
			{
				if (Labels.Count >= 1024)
				{
					Labels.Clear();
				}
				value = $"{need} ({inChests})";
				Labels[key] = value;
			}
			return value;
		}
	}
	[HarmonyPatch(typeof(Inventory), "CountItems")]
	internal static class CountItemsPatch
	{
		private static void Postfix(Inventory __instance, string name, int quality, ref int __result)
		{
			ChestScope.AddChestCount(__instance, name, quality, ref __result);
		}
	}
	[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
	{
		typeof(string),
		typeof(bool)
	})]
	internal static class HaveItemPatch
	{
		private static void Postfix(Inventory __instance, string name, ref bool __result)
		{
			if (!__result && ChestScope.Active)
			{
				int result = 0;
				ChestScope.AddChestCount(__instance, name, -1, ref result);
				if (result > 0)
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Inventory), "RemoveItem", new Type[]
	{
		typeof(string),
		typeof(int),
		typeof(int),
		typeof(bool)
	})]
	internal static class RemoveItemPatch
	{
		private static bool Prefix(Inventory __instance, string name, int amount, int itemQuality, bool worldLevelBased)
		{
			return !ChestScope.TryRemoveFromChests(__instance, name, amount, itemQuality, worldLevelBased);
		}
	}
	[BepInPlugin("com.despr0grammer.craftfromchestoptimized", "CraftFromChestOptimized", "1.0.0")]
	[BepInIncompatibility("com.teflonted.valheim.craftfromchests")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.despr0grammer.craftfromchestoptimized";

		public const string PluginName = "CraftFromChestOptimized";

		public const string PluginVersion = "1.0.0";

		private const string OriginalGuid = "com.teflonted.valheim.craftfromchests";

		private const float PruneInterval = 30f;

		internal static ManualLogSource Log;

		private ConfigEntry<KeyboardShortcut> _toggleKey;

		private Harmony _harmony;

		private float _nextPrune;

		private static readonly Type[] CorePatches = new Type[11]
		{
			typeof(ContainerAwakePatch),
			typeof(HaveRequirementItemsPatch),
			typeof(HaveRequirementsPiecePatch),
			typeof(HaveRequirementsRecipePatch),
			typeof(ConsumeResourcesPatch),
			typeof(GetFirstRequiredItemPatch),
			typeof(DoCraftingPatch),
			typeof(SetupRequirementPatch),
			typeof(CountItemsPatch),
			typeof(HaveItemPatch),
			typeof(RemoveItemPatch)
		};

		private static readonly Type[] OptionalPatches = new Type[1] { typeof(RequirementLabelPatch) };

		private void Awake()
		{
			//IL_0026: 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_0068: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Key that turns crafting from nearby chests on/off while playing.");
			if (!GameAccess.Ready)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Valheim internals changed (Container.CheckAccess/Save not found); mod disabled.");
				Disable();
				return;
			}
			_harmony = new Harmony("com.despr0grammer.craftfromchestoptimized");
			if (!ApplyPatches())
			{
				Disable();
				return;
			}
			ChestRegistry.SeedFromScene();
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded ({2} toggles it)", "CraftFromChestOptimized", "1.0.0", _toggleKey.Value));
		}

		private bool ApplyPatches()
		{
			Type[] corePatches = CorePatches;
			foreach (Type type in corePatches)
			{
				try
				{
					_harmony.PatchAll(type);
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Required patch " + type.Name + " failed, mod disabled: " + ex.Message));
					_harmony.UnpatchSelf();
					return false;
				}
			}
			corePatches = OptionalPatches;
			foreach (Type type2 in corePatches)
			{
				try
				{
					_harmony.PatchAll(type2);
				}
				catch (Exception ex2)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)("Optional patch " + type2.Name + " failed: " + ex2.Message));
				}
			}
			return true;
		}

		private void Disable()
		{
			ChestScope.SetEnabled(enabled: false);
			((Behaviour)this).enabled = false;
		}

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

		private void Update()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			ChestScope.EndFrameCheck();
			KeyboardShortcut value = _toggleKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && CanToggle())
			{
				Toggle();
			}
			if (Time.unscaledTime >= _nextPrune)
			{
				_nextPrune = Time.unscaledTime + 30f;
				ChestRegistry.Prune();
			}
		}

		private static bool CanToggle()
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible())
			{
				return !TextInput.IsVisible();
			}
			return false;
		}

		private void Toggle()
		{
			bool flag = !ChestScope.Enabled;
			ChestScope.SetEnabled(flag);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Craft from chests: " + (flag ? "ON" : "OFF")));
			((Character)Player.m_localPlayer).Message((MessageType)1, StatusText(flag), 0, (Sprite)null, false);
			if (InventoryGui.IsVisible())
			{
				GameAccess.RefreshCraftingPanel(InventoryGui.instance);
			}
		}

		private static string StatusText(bool on)
		{
			if (Localization.instance != null && Localization.instance.GetSelectedLanguage() == "Spanish")
			{
				if (!on)
				{
					return "Craftear desde cofres: DESACTIVADO";
				}
				return "Craftear desde cofres: ACTIVADO";
			}
			if (!on)
			{
				return "Craft from chests: OFF";
			}
			return "Craft from chests: ON";
		}
	}
}