Decompiled source of CraftFromChestsPlus v1.1.5

plugins\CraftFromChestsPlus.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CraftFromChestsPlus.Chest;
using CraftFromChestsPlus.Effects;
using CraftFromChestsPlus.Localization;
using CraftFromChestsPlus.Totem;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("PONEIS")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Craft and build from chests inside a Craft Totem zone (max 200 m)")]
[assembly: AssemblyFileVersion("1.1.5.0")]
[assembly: AssemblyInformationalVersion("1.1.5+1fefb8f7be7537233096a5bace21382c155c79a4")]
[assembly: AssemblyProduct("CraftFromChestsPlus")]
[assembly: AssemblyTitle("CraftFromChestsPlus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.5.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 CraftFromChestsPlus
{
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> Range;

		internal static ConfigEntry<bool> EnableCraftFromChests;

		internal static ConfigEntry<bool> EnableBuildFromChests;

		internal static ConfigEntry<bool> EnableSmeltFromChests;

		internal static ConfigEntry<bool> RequireTotem;

		internal static ConfigEntry<KeyCode> RangeHoldKey;

		internal static ConfigEntry<bool> BlockCameraZoom;

		internal static ConfigEntry<float> ScrollStep;

		internal static ConfigEntry<float> MaxAdjustDistance;

		internal static ConfigEntry<bool> ShowAreaMarker;

		internal static ConfigEntry<bool> VisualFeedback;

		internal static ConfigEntry<bool> FlyingItemEffect;

		internal static ConfigEntry<string> Language;

		internal static void Bind(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			Enabled = config.Bind<bool>("General", "Enabled", true, "Master switch for CraftFromChestsPlus.");
			Range = config.Bind<float>("General", "Range", 50f, new ConfigDescription("Default zone / chest-pull radius (meters). With a totem, per-totem Alt+scroll can override.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 200f), Array.Empty<object>()));
			Range.SettingChanged += delegate
			{
				NearbyChestService.Invalidate();
			};
			RequireTotem = config.Bind<bool>("Activation", "RequireTotem", true, "If true: craft/build/smelt from chests only inside a placed Craft Totem zone. If false: always active around the player (uses Range). Edit via Configuration Manager / Mod Settings.");
			EnableCraftFromChests = config.Bind<bool>("Features", "EnableCraftFromChests", true, "Use chests for workbench / inventory crafting when activation allows.");
			EnableBuildFromChests = config.Bind<bool>("Features", "EnableBuildFromChests", true, "Use chests for hammer building when activation allows.");
			EnableSmeltFromChests = config.Bind<bool>("Features", "EnableSmeltFromChests", true, "Use chests for smelter / kiln / furnace ore & fuel when activation allows.");
			RangeHoldKey = config.Bind<KeyCode>("Controls", "RangeHoldKey", (KeyCode)308, "Hold this key and scroll while looking at a Craft Totem to change its radius. Default LeftAlt.");
			BlockCameraZoom = config.Bind<bool>("Controls", "BlockCameraZoom", true, "While RangeHoldKey is held, block camera zoom so scroll only changes totem range.");
			ScrollStep = config.Bind<float>("Controls", "ScrollStep", 2f, new ConfigDescription("Meters added/removed per scroll tick.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 20f), Array.Empty<object>()));
			MaxAdjustDistance = config.Bind<float>("Controls", "MaxAdjustDistance", 12f, new ConfigDescription("Max distance to a totem for Alt+scroll adjust.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 40f), Array.Empty<object>()));
			ShowAreaMarker = config.Bind<bool>("Controls", "ShowAreaMarker", true, "Show the totem area circle while adjusting range.");
			VisualFeedback = config.Bind<bool>("Feedback", "VisualFeedback", true, "Play SmartContainers-style VFX/SFX when items are pulled from chests.");
			FlyingItemEffect = config.Bind<bool>("Feedback", "FlyingItemEffect", true, "Spawn a short flying item visual from the chest toward you when materials are pulled.");
			Language = config.Bind<string>("Localization", "Language", "pt-BR", "Language for CraftFromChestsPlus messages. Values: Auto, English, Portuguese, pt-BR.");
			Language.SettingChanged += delegate
			{
				Loc.ApplyLanguagePreference();
			};
		}

		internal static bool IsRangeHoldKeyDown()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Invalid comparison between Unknown and I4
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Invalid comparison between Unknown and I4
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			KeyCode value = RangeHoldKey.Value;
			if ((int)value == 308 || (int)value == 307)
			{
				if (!Input.GetKey((KeyCode)308))
				{
					return Input.GetKey((KeyCode)307);
				}
				return true;
			}
			if ((int)value == 306 || (int)value == 305)
			{
				if (!Input.GetKey((KeyCode)306))
				{
					return Input.GetKey((KeyCode)305);
				}
				return true;
			}
			if ((int)value == 304 || (int)value == 303)
			{
				if (!Input.GetKey((KeyCode)304))
				{
					return Input.GetKey((KeyCode)303);
				}
				return true;
			}
			return Input.GetKey(value);
		}
	}
	[BepInPlugin("poneis.valheim.CraftFromChestsPlus", "CraftFromChestsPlus", "1.1.5")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "poneis.valheim.CraftFromChestsPlus";

		public const string PluginName = "CraftFromChestsPlus";

		public const string PluginVersion = "1.1.5";

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			Loc.Init();
			TotemPieceFactory.Init();
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "poneis.valheim.CraftFromChestsPlus");
			((Component)this).gameObject.AddComponent<TotemRangeInputListener>();
			Log.LogInfo((object)string.Format("{0} {1} loaded. Default range={2:0.#} m", "CraftFromChestsPlus", "1.1.5", ModConfig.Range.Value));
		}
	}
}
namespace CraftFromChestsPlus.Totem
{
	internal class CraftTotem : MonoBehaviour, Hoverable
	{
		internal static readonly int RangeHash = StringExtensionMethods.GetStableHashCode("cfc_range");

		private GameObject _marker;

		private CircleProjector _projector;

		private float _hideMarkerAt;

		private bool _forceMarker;

		private ZNetView _nview;

		private string _displayNameToken = "cfc_totem_sign_name";

		internal void SetDisplayNameToken(string token)
		{
			if (!string.IsNullOrEmpty(token))
			{
				_displayNameToken = token;
			}
		}

		private void Awake()
		{
			_nview = ((Component)this).GetComponent<ZNetView>();
			if (IsPlacedInstance())
			{
				EnsureMarker();
				TotemZoneService.Register(this);
			}
		}

		private void Start()
		{
			if (IsPlacedInstance())
			{
				EnsureMarker();
				TotemZoneService.Register(this);
			}
		}

		private void OnDestroy()
		{
			TotemZoneService.Unregister(this);
		}

		internal bool IsPlacedInstance()
		{
			if ((Object)(object)this == (Object)null || (Object)(object)((Component)this).transform == (Object)null)
			{
				return false;
			}
			try
			{
				if ((Object)(object)_nview == (Object)null)
				{
					_nview = ((Component)this).GetComponent<ZNetView>();
				}
				if ((Object)(object)_nview == (Object)null || !_nview.IsValid())
				{
					return false;
				}
				ZDO zDO = _nview.GetZDO();
				return zDO != null && zDO.IsValid();
			}
			catch
			{
				return false;
			}
		}

		internal bool IsValid()
		{
			return IsPlacedInstance();
		}

		internal float GetRange()
		{
			float effectiveRange = NearbyChestService.EffectiveRange;
			try
			{
				ZDO val = (((Object)(object)_nview != (Object)null) ? _nview.GetZDO() : null);
				if (val != null && val.IsValid())
				{
					float num = val.GetFloat(RangeHash, -1f);
					if (num >= 5f)
					{
						return Mathf.Clamp(num, 5f, 200f);
					}
				}
			}
			catch
			{
			}
			return effectiveRange;
		}

		internal void SetRange(float range)
		{
			range = Mathf.Clamp(range, 5f, 200f);
			try
			{
				ZDO val = (((Object)(object)_nview != (Object)null) ? _nview.GetZDO() : null);
				if (val == null || !val.IsValid())
				{
					return;
				}
				val.Set(RangeHash, range);
			}
			catch
			{
			}
			ApplyRadius();
			NearbyChestService.Invalidate();
		}

		public string GetHoverName()
		{
			return Loc.T(_displayNameToken);
		}

		public string GetHoverText()
		{
			ShowMarkerTemporarily();
			float range = GetRange();
			string text = BuildFeatureHint();
			return Localization.instance.Localize(Loc.T(_displayNameToken) + "\n" + Loc.Tf("cfc_totem_hover", range) + "\n" + Loc.T("cfc_totem_scroll_hint") + (string.IsNullOrEmpty(text) ? "" : ("\n" + text)));
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		private static string BuildFeatureHint()
		{
			List<string> list = new List<string>(3);
			if (ModConfig.EnableCraftFromChests.Value)
			{
				list.Add(Loc.T("cfc_feat_craft"));
			}
			if (ModConfig.EnableBuildFromChests.Value)
			{
				list.Add(Loc.T("cfc_feat_build"));
			}
			if (ModConfig.EnableSmeltFromChests.Value)
			{
				list.Add(Loc.T("cfc_feat_smelt"));
			}
			if (list.Count != 0)
			{
				return string.Join(" · ", list);
			}
			return Loc.T("cfc_feat_none");
		}

		internal void ShowMarkerTemporarily()
		{
			EnsureMarker();
			if (!((Object)(object)_marker == (Object)null))
			{
				TotemZoneService.HideAllMarkersExcept(this);
				ApplyRadius();
				_marker.SetActive(true);
				if (!_forceMarker)
				{
					_hideMarkerAt = Time.time + 0.35f;
				}
			}
		}

		internal void ShowMarkerForced()
		{
			_forceMarker = true;
			ShowMarkerTemporarily();
		}

		internal void HideMarker()
		{
			_forceMarker = false;
			if ((Object)(object)_marker != (Object)null)
			{
				_marker.SetActive(false);
			}
		}

		private void LateUpdate()
		{
			if (!_forceMarker && (Object)(object)_marker != (Object)null && _marker.activeSelf && Time.time >= _hideMarkerAt)
			{
				_marker.SetActive(false);
			}
		}

		private void EnsureMarker()
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_marker != (Object)null))
			{
				Transform val = ((Component)this).transform.Find("cfc_area_marker");
				if ((Object)(object)val != (Object)null)
				{
					_marker = ((Component)val).gameObject;
					_projector = _marker.GetComponentInChildren<CircleProjector>(true);
					_marker.SetActive(false);
					return;
				}
				_marker = new GameObject("cfc_area_marker");
				_marker.transform.SetParent(((Component)this).transform, false);
				_marker.transform.localPosition = Vector3.zero;
				_projector = _marker.AddComponent<CircleProjector>();
				_projector.m_radius = GetRange();
				_projector.m_nrOfSegments = 64;
				_marker.SetActive(false);
			}
		}

		internal void ApplyRadius()
		{
			float range = GetRange();
			if ((Object)(object)_projector != (Object)null)
			{
				_projector.m_radius = range;
			}
		}

		internal static void SetupPrefabMarker(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.transform.Find("cfc_area_marker") != (Object)null)
			{
				return;
			}
			GameObject val = null;
			try
			{
				val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("piece_workbench") : null);
			}
			catch
			{
			}
			CraftingStation val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<CraftingStation>() : null);
			if (!((Object)(object)val2?.m_areaMarker == (Object)null))
			{
				GameObject obj2 = Object.Instantiate<GameObject>(val2.m_areaMarker, prefab.transform);
				((Object)obj2).name = "cfc_area_marker";
				obj2.SetActive(false);
				CircleProjector componentInChildren = obj2.GetComponentInChildren<CircleProjector>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.m_radius = NearbyChestService.EffectiveRange;
					componentInChildren.m_nrOfSegments = 64;
				}
			}
		}
	}
	internal class CraftZoneLabel : MonoBehaviour
	{
		private Transform _label;

		private TextMesh _text;

		private void Start()
		{
			EnsureLabel();
		}

		private void EnsureLabel()
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_0064: 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)
			if (!((Object)(object)_label != (Object)null))
			{
				Transform val = ((Component)this).transform.Find("cfc_craft_zone_label");
				GameObject val2;
				if ((Object)(object)val != (Object)null)
				{
					val2 = ((Component)val).gameObject;
				}
				else
				{
					val2 = new GameObject("cfc_craft_zone_label");
					val2.transform.SetParent(((Component)this).transform, false);
					val2.transform.localPosition = new Vector3(0f, 1.55f, 0f);
				}
				_label = val2.transform;
				_text = val2.GetComponent<TextMesh>();
				if ((Object)(object)_text == (Object)null)
				{
					_text = val2.AddComponent<TextMesh>();
				}
				_text.text = Loc.T("cfc_zone_tag");
				_text.anchor = (TextAnchor)4;
				_text.alignment = (TextAlignment)1;
				_text.characterSize = 0.06f;
				_text.fontSize = 48;
				_text.color = new Color(1f, 0.82f, 0.35f, 1f);
				_text.fontStyle = (FontStyle)1;
			}
		}

		private void LateUpdate()
		{
			//IL_0052: 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)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			EnsureLabel();
			if (!((Object)(object)_label == (Object)null))
			{
				Camera val = Camera.main;
				if ((Object)(object)val == (Object)null && (Object)(object)GameCamera.instance != (Object)null)
				{
					val = ((Component)GameCamera.instance).GetComponent<Camera>();
				}
				if (!((Object)(object)val == (Object)null))
				{
					_label.rotation = Quaternion.LookRotation(_label.position - ((Component)val).transform.position);
				}
			}
		}
	}
	internal static class TotemPieceFactory
	{
		internal const string SignPieceName = "cfc_craft_totem_sign";

		internal const string StatuePieceName = "cfc_craft_totem_statue";

		internal const string LegacyPieceName = "cfc_craft_totem";

		private static bool _registered;

		internal static void Init()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
			PieceManager.OnPiecesRegistered -= OnPiecesRegistered;
			PieceManager.OnPiecesRegistered += OnPiecesRegistered;
		}

		internal static bool IsTotemPrefabName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			switch (name)
			{
			default:
				if (!name.StartsWith("cfc_craft_totem_sign") && !name.StartsWith("cfc_craft_totem_statue"))
				{
					return name.StartsWith("cfc_craft_totem");
				}
				break;
			case "cfc_craft_totem_sign":
			case "cfc_craft_totem_statue":
			case "cfc_craft_totem":
				break;
			}
			return true;
		}

		private static void OnVanillaPrefabsAvailable()
		{
			if (_registered)
			{
				return;
			}
			try
			{
				RegisterLocalization();
				RegisterPiece("cfc_craft_totem_sign", "sign", "$cfc_totem_sign_name", "$cfc_totem_sign_desc");
				RegisterPiece("cfc_craft_totem_statue", "sign", "$cfc_totem_statue_name", "$cfc_totem_statue_desc");
				RegisterPiece("cfc_craft_totem", "sign", "$cfc_totem_sign_name", "$cfc_totem_sign_desc");
				_registered = true;
				Plugin.Log.LogInfo((object)"Registered Craft Totem sign pieces.");
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Failed to register Craft Totems: {arg}");
			}
		}

		private static RequirementConfig[] TotemRequirements()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			return (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("Wood", 20, 0, true),
				new RequirementConfig("Resin", 10, 0, true),
				new RequirementConfig("Bronze", 5, 0, true)
			};
		}

		private static void RegisterPiece(string name, string basePrefab, string nameToken, string descToken)
		{
			//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)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			if (PieceManager.Instance.GetPiece(name) == null)
			{
				PieceConfig val = new PieceConfig
				{
					Name = nameToken,
					Description = descToken,
					PieceTable = PieceTables.Hammer,
					Category = PieceCategories.Misc,
					CraftingStation = CraftingStations.Workbench,
					Requirements = TotemRequirements()
				};
				PieceManager.Instance.AddPiece(new CustomPiece(name, basePrefab, val));
			}
		}

		private static void OnPiecesRegistered()
		{
			FinalizePiece("cfc_craft_totem_sign", "cfc_totem_sign_name");
			FinalizePiece("cfc_craft_totem_statue", "cfc_totem_statue_name");
			FinalizePiece("cfc_craft_totem", "cfc_totem_sign_name");
		}

		private static void FinalizePiece(string prefabName, string displayToken)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(prefabName);
			if ((Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Craft Totem prefab '" + prefabName + "' not found after registration."));
				return;
			}
			CraftTotem craftTotem = prefab.GetComponent<CraftTotem>();
			if ((Object)(object)craftTotem == (Object)null)
			{
				craftTotem = prefab.AddComponent<CraftTotem>();
			}
			craftTotem.SetDisplayNameToken(displayToken);
			CraftTotem.SetupPrefabMarker(prefab);
			Piece component = prefab.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_name = "$" + displayToken;
				component.m_description = "$" + displayToken.Replace("_name", "_desc");
				component.m_canBeRemoved = true;
				((StaticTarget)component).m_primaryTarget = false;
			}
			WearNTear component2 = prefab.GetComponent<WearNTear>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_noRoofWear = false;
				component2.m_noSupportWear = false;
			}
			EnsureSignIcon(prefab);
			StripLegacyFulingVisual(prefab);
			if ((Object)(object)prefab.GetComponent<CraftZoneLabel>() == (Object)null)
			{
				prefab.AddComponent<CraftZoneLabel>();
			}
		}

		private static void StripLegacyFulingVisual(GameObject prefab)
		{
			Transform val = prefab.transform.Find("cfc_fuling_visual");
			if ((Object)(object)val != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)((Component)val).gameObject);
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null))
				{
					string name = ((Object)((Component)val2).transform).name;
					if (name.IndexOf("cfc_area", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("cfc_craft_zone", StringComparison.OrdinalIgnoreCase) < 0)
					{
						val2.enabled = true;
					}
				}
			}
			Sign component = prefab.GetComponent<Sign>();
			if ((Object)(object)component != (Object)null)
			{
				((Behaviour)component).enabled = true;
			}
		}

		private static void EnsureSignIcon(GameObject prefab)
		{
			Piece component = prefab.GetComponent<Piece>();
			if (!((Object)(object)component == (Object)null))
			{
				GameObject prefab2 = PrefabManager.Instance.GetPrefab("sign");
				Piece val = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<Piece>() : null);
				if ((Object)(object)val != (Object)null && (Object)(object)val.m_icon != (Object)null)
				{
					component.m_icon = val.m_icon;
				}
			}
		}

		private static void RegisterLocalization()
		{
			string text = "{\"cfc_totem_sign_name\":\"Craft Totem (Sign)\",\"cfc_totem_sign_desc\":\"Placed craft-zone sign. Activates craft/build/smelt from nearby chests for all players in range. Hammer → Misc near a Workbench.\",\"cfc_totem_statue_name\":\"Craft Totem (Zone Sign)\",\"cfc_totem_statue_desc\":\"Normal sign with a Craft Zone label. Same zone rules. Hammer → Misc near a Workbench.\",\"cfc_totem_name\":\"Craft Totem\",\"cfc_totem_desc\":\"Activates crafting, building and smelting from nearby chests for all players within range.\",\"cfc_zone_tag\":\"Craft Zone\"}";
			string text2 = "{\"cfc_totem_sign_name\":\"Totem de Craft (Placa)\",\"cfc_totem_sign_desc\":\"Placa de zona de craft. Ativa craft/construção/fundição a partir de baús. Martelo → Misc perto da Bancada.\",\"cfc_totem_statue_name\":\"Totem de Craft (Placa Zone)\",\"cfc_totem_statue_desc\":\"Placa normal com etiqueta Craft Zone. Mesmas regras. Martelo → Misc perto da Bancada.\",\"cfc_totem_name\":\"Totem de Craft\",\"cfc_totem_desc\":\"Ativa craft, construção e fundição a partir de baús próximos para todos os jogadores no alcance.\",\"cfc_zone_tag\":\"Craft Zone\"}";
			LocalizationManager.Instance.AddJson("English", text);
			LocalizationManager.Instance.AddJson("Portuguese_Brazilian", text2);
		}
	}
	internal static class TotemRangeService
	{
		private static CraftTotem _lastMarker;

		private static float _nextMsg;

		internal static void TryAdjustFromScroll(Player player, float scrollY)
		{
			if ((Object)(object)player == (Object)null || Mathf.Abs(scrollY) < 0.01f)
			{
				return;
			}
			CraftTotem craftTotem = TotemZoneService.FindAdjustTarget(player);
			if ((Object)(object)craftTotem == (Object)null)
			{
				if (Time.time >= _nextMsg)
				{
					_nextMsg = Time.time + 0.5f;
					((Character)player).Message((MessageType)2, Loc.T("cfc_msg_no_totem"), 0, (Sprite)null, false);
				}
				return;
			}
			float value = ModConfig.ScrollStep.Value;
			float num = ((scrollY > 0f) ? value : (0f - value));
			float range = craftTotem.GetRange() + num;
			craftTotem.SetRange(range);
			if (ModConfig.ShowAreaMarker.Value)
			{
				if ((Object)(object)_lastMarker != (Object)null && (Object)(object)_lastMarker != (Object)(object)craftTotem)
				{
					_lastMarker.HideMarker();
				}
				craftTotem.ShowMarkerForced();
				_lastMarker = craftTotem;
			}
			((Character)player).Message((MessageType)2, Loc.Tf("cfc_msg_range", craftTotem.GetRange()), 0, (Sprite)null, false);
		}

		internal static void TickMarkers()
		{
			if (!ModConfig.IsRangeHoldKeyDown() && (Object)(object)_lastMarker != (Object)null)
			{
				_lastMarker.HideMarker();
				_lastMarker = null;
			}
		}
	}
	internal sealed class TotemRangeInputListener : MonoBehaviour
	{
		private void Update()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			TotemRangeService.TickMarkers();
			if (!ModConfig.IsRangeHoldKeyDown())
			{
				return;
			}
			float y = Input.mouseScrollDelta.y;
			if (!(Mathf.Abs(y) < 0.01f))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !Console.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()))
				{
					TotemRangeService.TryAdjustFromScroll(localPlayer, y);
				}
			}
		}
	}
	internal static class TotemZoneService
	{
		private static readonly List<CraftTotem> Totems = new List<CraftTotem>();

		private static bool _wasInZone;

		private static float _nextToast;

		private const float ToastCooldown = 4f;

		internal static void Register(CraftTotem totem)
		{
			if (!((Object)(object)totem == (Object)null) && totem.IsPlacedInstance() && !Totems.Contains(totem))
			{
				Totems.Add(totem);
			}
		}

		internal static void Unregister(CraftTotem totem)
		{
			if (!((Object)(object)totem == (Object)null))
			{
				Totems.Remove(totem);
			}
		}

		internal static void Prune()
		{
			for (int num = Totems.Count - 1; num >= 0; num--)
			{
				CraftTotem craftTotem = Totems[num];
				if ((Object)(object)craftTotem == (Object)null || !craftTotem.IsPlacedInstance())
				{
					Totems.RemoveAt(num);
				}
			}
		}

		internal static bool IsInZone(Player player)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)player == (Object)null)
			{
				return false;
			}
			if (!ModConfig.RequireTotem.Value)
			{
				return true;
			}
			Prune();
			if (Totems.Count == 0)
			{
				return false;
			}
			Vector3 position = ((Component)player).transform.position;
			for (int i = 0; i < Totems.Count; i++)
			{
				CraftTotem craftTotem = Totems[i];
				if (!((Object)(object)craftTotem == (Object)null) && craftTotem.IsPlacedInstance())
				{
					float range = craftTotem.GetRange();
					float num = range * range;
					Vector3 val = ((Component)craftTotem).transform.position - position;
					if (((Vector3)(ref val)).sqrMagnitude <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		internal static float GetActivePullRange(Player player)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return NearbyChestService.EffectiveRange;
			}
			if (!ModConfig.RequireTotem.Value)
			{
				return NearbyChestService.EffectiveRange;
			}
			CraftTotem craftTotem = FindCoveringTotem(((Component)player).transform.position);
			if ((Object)(object)craftTotem != (Object)null)
			{
				return craftTotem.GetRange();
			}
			return NearbyChestService.EffectiveRange;
		}

		internal static CraftTotem FindCoveringTotem(Vector3 pos)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			Prune();
			CraftTotem result = null;
			float num = float.MaxValue;
			for (int i = 0; i < Totems.Count; i++)
			{
				CraftTotem craftTotem = Totems[i];
				if (!((Object)(object)craftTotem == (Object)null) && craftTotem.IsPlacedInstance())
				{
					float range = craftTotem.GetRange();
					Vector3 val = ((Component)craftTotem).transform.position - pos;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude > range * range) && sqrMagnitude < num)
					{
						num = sqrMagnitude;
						result = craftTotem;
					}
				}
			}
			return result;
		}

		internal static CraftTotem FindNearest(Vector3 pos, out float distance)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			Prune();
			CraftTotem craftTotem = null;
			float num = float.MaxValue;
			for (int i = 0; i < Totems.Count; i++)
			{
				CraftTotem craftTotem2 = Totems[i];
				if (!((Object)(object)craftTotem2 == (Object)null) && craftTotem2.IsPlacedInstance())
				{
					Vector3 val = ((Component)craftTotem2).transform.position - pos;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						craftTotem = craftTotem2;
					}
				}
			}
			distance = (((Object)(object)craftTotem != (Object)null) ? Mathf.Sqrt(num) : float.MaxValue);
			return craftTotem;
		}

		internal static CraftTotem FindAdjustTarget(Player player)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			float value = ModConfig.MaxAdjustDistance.Value;
			CraftTotem result = null;
			float num = float.MaxValue;
			Vector3 eyePoint = ((Character)player).GetEyePoint();
			Vector3 lookDir = ((Character)player).GetLookDir();
			Prune();
			for (int i = 0; i < Totems.Count; i++)
			{
				CraftTotem craftTotem = Totems[i];
				if ((Object)(object)craftTotem == (Object)null || !craftTotem.IsPlacedInstance())
				{
					continue;
				}
				float num2 = Vector3.Distance(((Component)player).transform.position, ((Component)craftTotem).transform.position);
				if (num2 > value)
				{
					continue;
				}
				Vector3 val = ((Component)craftTotem).transform.position - eyePoint;
				Vector3 normalized = ((Vector3)(ref val)).normalized;
				float num3 = Vector3.Dot(lookDir, normalized);
				if (!(num3 < 0.25f))
				{
					float num4 = num2 * (1.5f - num3);
					if (num4 < num)
					{
						num = num4;
						result = craftTotem;
					}
				}
			}
			return result;
		}

		internal static void Tick(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				bool flag = IsInZone(player);
				if (flag && !_wasInZone && Time.time >= _nextToast)
				{
					_nextToast = Time.time + 4f;
					float activePullRange = GetActivePullRange(player);
					string key = (ModConfig.RequireTotem.Value ? "cfc_zone_enter" : "cfc_zone_enter_always");
					((Character)player).Message((MessageType)2, Loc.Tf(key, activePullRange), 0, (Sprite)null, false);
				}
				_wasInZone = flag;
			}
		}

		internal static void HideAllMarkersExcept(CraftTotem keep)
		{
			for (int i = 0; i < Totems.Count; i++)
			{
				CraftTotem craftTotem = Totems[i];
				if (!((Object)(object)craftTotem == (Object)null) && !((Object)(object)craftTotem == (Object)(object)keep))
				{
					craftTotem.HideMarker();
				}
			}
		}
	}
}
namespace CraftFromChestsPlus.Patches
{
	[HarmonyPatch]
	internal static class CameraZoomBlockPatch
	{
		private static float _savedDistance;

		private static bool _restore;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Prefix(GameCamera __instance)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			_restore = false;
			if (ModConfig.BlockCameraZoom.Value && ModConfig.IsRangeHoldKeyDown() && Input.mouseScrollDelta.y != 0f && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				_savedDistance = __instance.m_distance;
				_restore = true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
		private static void Postfix(GameCamera __instance)
		{
			if (_restore)
			{
				__instance.m_distance = _savedDistance;
			}
		}
	}
	[HarmonyPatch]
	internal static class ConsumePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "ConsumeResources")]
		private static bool ConsumeResourcesPrefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier)
		{
			return Consume(__instance, requirements, qualityLevel, multiplier);
		}

		private static bool Consume(Player __instance, Requirement[] requirements, int qualityLevel, int multiplier)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)__instance == (Object)null || requirements == null)
			{
				return true;
			}
			Inventory inventory = ((Humanoid)__instance).GetInventory();
			if (inventory == null)
			{
				return true;
			}
			Vector3 position = ((Component)__instance).transform.position;
			bool flag = CountPatches.ShouldQueryChests();
			foreach (Requirement val in requirements)
			{
				if (val == null || (Object)(object)val.m_resItem == (Object)null)
				{
					continue;
				}
				int num = val.GetAmount(qualityLevel) * Mathf.Max(1, multiplier);
				if (num > 0)
				{
					string name = val.m_resItem.m_itemData.m_shared.m_name;
					CountPatches.IncludeChests = false;
					int num2;
					try
					{
						num2 = inventory.CountItems(name, -1, true);
					}
					finally
					{
						CountPatches.IncludeChests = true;
					}
					int num3 = Mathf.Min(num2, num);
					if (num3 > 0)
					{
						inventory.RemoveItem(name, num3, -1, true);
					}
					int num4 = num - num3;
					if (num4 > 0 && flag)
					{
						NearbyChestService.RemoveFromChests(name, num4, position);
					}
				}
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class CountPatches
	{
		internal static bool IncludeChests = true;

		private static bool IsLocalPlayerInventory(Inventory inventory)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && inventory != null)
			{
				return inventory == ((Humanoid)localPlayer).GetInventory();
			}
			return false;
		}

		internal static bool ShouldQueryChests()
		{
			if (!ModConfig.Enabled.Value || !IncludeChests)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			if (!TotemZoneService.IsInZone(localPlayer))
			{
				return false;
			}
			try
			{
				if (((Character)localPlayer).InPlaceMode())
				{
					return ModConfig.EnableBuildFromChests.Value;
				}
			}
			catch
			{
			}
			return ModConfig.EnableCraftFromChests.Value;
		}

		internal static bool ShouldQueryChestsForSmelt()
		{
			if (!ModConfig.Enabled.Value || !ModConfig.EnableSmeltFromChests.Value)
			{
				return false;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return TotemZoneService.IsInZone(localPlayer);
			}
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Inventory), "CountItems")]
		private static void CountItemsPostfix(Inventory __instance, string name, int quality, bool matchWorldLevel, ref int __result)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (ShouldQueryChests() && !string.IsNullOrEmpty(name) && IsLocalPlayerInventory(__instance))
			{
				Player localPlayer = Player.m_localPlayer;
				__result += NearbyChestService.CountInChests(name, quality, matchWorldLevel, ((Component)localPlayer).transform.position);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Inventory), "HaveItem", new Type[]
		{
			typeof(string),
			typeof(bool)
		})]
		private static void HaveItemPostfix(Inventory __instance, string name, bool matchWorldLevel, ref bool __result)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			if (!__result && ShouldQueryChests() && !string.IsNullOrEmpty(name) && IsLocalPlayerInventory(__instance))
			{
				Player localPlayer = Player.m_localPlayer;
				__result = NearbyChestService.CountInChests(name, -1, matchWorldLevel, ((Component)localPlayer).transform.position) > 0;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")]
		private static void UpdateRecipeListPrefix()
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (ModConfig.Enabled.Value && ModConfig.EnableCraftFromChests.Value)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && TotemZoneService.IsInZone(localPlayer))
				{
					NearbyChestService.InvalidateCounts();
					NearbyChestService.GetNearby(((Component)localPlayer).transform.position);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class RequirementPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "SetupRequirement")]
		private static void SetupRequirementPostfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier)
		{
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)elementRoot == (Object)null || (Object)(object)req?.m_resItem == (Object)null || (Object)(object)player == (Object)null)
			{
				return;
			}
			Transform val = elementRoot.Find("res_amount");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			TMP_Text component = ((Component)val).GetComponent<TMP_Text>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			int num = req.GetAmount(quality) * Mathf.Max(1, craftMultiplier);
			if (num > 0)
			{
				string name = req.m_resItem.m_itemData.m_shared.m_name;
				int num2 = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
				component.text = num2 + "/" + num;
				bool flag = num2 >= num;
				if (!flag && craft)
				{
					flag = (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)25);
				}
				if (flag)
				{
					((Graphic)component).color = Color.white;
					return;
				}
				bool flag2 = Mathf.Sin(Time.time * 10f) > 0f;
				((Graphic)component).color = (flag2 ? Color.red : Color.white);
			}
		}
	}
	[HarmonyPatch]
	internal static class SmelterPatches
	{
		private static bool CanPullFromChests(Humanoid user)
		{
			Player val = (Player)(object)((user is Player) ? user : null);
			if (val != null && CountPatches.ShouldQueryChestsForSmelt())
			{
				return TotemZoneService.IsInZone(val);
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Smelter), "OnAddOre")]
		private static bool OnAddOrePrefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
		{
			//IL_0066: 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)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)user == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!CanPullFromChests(user))
			{
				return true;
			}
			if (item != null)
			{
				return true;
			}
			Inventory inventory = user.GetInventory();
			if (inventory != null && __instance.FindCookableItem(inventory) != null)
			{
				return true;
			}
			Vector3 position = ((Component)user).transform.position;
			if (!NearbyChestService.TryFindOreInChests(__instance, position, out var prefabName, out var sharedName))
			{
				return true;
			}
			if (!__instance.IsItemAllowed(prefabName))
			{
				((Character)user).Message((MessageType)2, "$msg_wontwork", 0, (Sprite)null, false);
				__result = false;
				return false;
			}
			if (__instance.GetQueueSize() >= __instance.m_maxOre)
			{
				((Character)user).Message((MessageType)2, "$msg_itsfull", 0, (Sprite)null, false);
				__result = false;
				return false;
			}
			if (NearbyChestService.RemoveFromChests(sharedName, 1, position) <= 0)
			{
				return true;
			}
			((Character)user).Message((MessageType)2, "$msg_added " + sharedName, 0, (Sprite)null, false);
			__instance.m_nview.InvokeRPC("RPC_AddOre", new object[2] { prefabName, false });
			__instance.m_addedOreTime = Time.time;
			if (__instance.m_addOreAnimationDuration > 0f)
			{
				__instance.SetAnimation(true);
			}
			__result = true;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Smelter), "OnAddFuel")]
		private static bool OnAddFuelPrefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)user == (Object)null || (Object)(object)__instance.m_fuelItem == (Object)null)
			{
				return true;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!CanPullFromChests(user))
			{
				return true;
			}
			string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
			if (item != null && item.m_shared.m_name != name)
			{
				return true;
			}
			if (__instance.GetFuel() > (float)(__instance.m_maxFuel - 1))
			{
				return true;
			}
			Inventory inventory = user.GetInventory();
			bool flag = false;
			if (inventory != null)
			{
				CountPatches.IncludeChests = false;
				try
				{
					flag = inventory.HaveItem(name, true);
				}
				finally
				{
					CountPatches.IncludeChests = true;
				}
			}
			if (flag)
			{
				return true;
			}
			Vector3 position = ((Component)user).transform.position;
			if (NearbyChestService.CountInChests(name, position) <= 0)
			{
				return true;
			}
			if (NearbyChestService.RemoveFromChests(name, 1, position) <= 0)
			{
				return true;
			}
			((Character)user).Message((MessageType)2, "$msg_added " + name, 0, (Sprite)null, false);
			__instance.m_nview.InvokeRPC("RPC_AddFuel", Array.Empty<object>());
			__result = true;
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Smelter), "CanUseItems")]
		private static void CanUseItemsPostfix(Smelter __instance, Player player, Switch switchRef, bool sendErrorMessage, ref bool __result)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			if (__result || !ModConfig.Enabled.Value || (Object)(object)__instance == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !CountPatches.ShouldQueryChestsForSmelt())
			{
				return;
			}
			Vector3 position = ((Component)player).transform.position;
			if (__instance.m_conversion != null && NearbyChestService.TryFindOreInChests(__instance, position, out var _, out var _) && __instance.GetQueueSize() < __instance.m_maxOre)
			{
				__result = true;
			}
			else if ((Object)(object)__instance.m_fuelItem != (Object)null)
			{
				string name = __instance.m_fuelItem.m_itemData.m_shared.m_name;
				if (__instance.GetFuel() <= (float)(__instance.m_maxFuel - 1) && NearbyChestService.CountInChests(name, position) > 0)
				{
					__result = true;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class TotemZonePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdatePostfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				TotemZoneService.Tick(__instance);
			}
		}
	}
}
namespace CraftFromChestsPlus.Localization
{
	internal static class Loc
	{
		private static readonly Dictionary<string, Dictionary<string, string>> Tables = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);

		private static string _activeCode = "en";

		private static string LangDir => Path.Combine(Paths.ConfigPath, "CraftFromChestsPlus", "lang");

		internal static void Init()
		{
			EnsureLangFolder();
			LoadEmbedded("en");
			LoadEmbedded("pt");
			LoadDiskOverrides();
			ApplyLanguagePreference();
			Plugin.Log.LogInfo((object)("Localization ready (active=" + _activeCode + ", files in " + LangDir + ")"));
		}

		internal static string T(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return key;
			}
			if (Tables.TryGetValue(_activeCode, out var value) && value.TryGetValue(key, out var value2))
			{
				return value2;
			}
			if (Tables.TryGetValue("en", out var value3) && value3.TryGetValue(key, out value2))
			{
				return value2;
			}
			return key;
		}

		internal static string Tf(string key, params object[] args)
		{
			try
			{
				return string.Format(T(key), args);
			}
			catch (FormatException)
			{
				return T(key);
			}
		}

		private static void EnsureLangFolder()
		{
			Directory.CreateDirectory(LangDir);
			WriteEmbedded("en");
			WriteEmbedded("pt");
		}

		private static void WriteEmbedded(string code)
		{
			string path = Path.Combine(LangDir, code + ".json");
			string text = ReadEmbedded(code);
			if (!string.IsNullOrEmpty(text))
			{
				File.WriteAllText(path, text, Encoding.UTF8);
			}
		}

		private static void LoadEmbedded(string code)
		{
			string text = ReadEmbedded(code);
			if (!string.IsNullOrEmpty(text))
			{
				Tables[code] = ParseFlatJson(text);
			}
		}

		private static void LoadDiskOverrides()
		{
			if (!Directory.Exists(LangDir))
			{
				return;
			}
			string[] files = Directory.GetFiles(LangDir, "*.json");
			foreach (string text in files)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				try
				{
					Dictionary<string, string> dictionary = ParseFlatJson(File.ReadAllText(text, Encoding.UTF8));
					if (dictionary.Count == 0)
					{
						continue;
					}
					if (!Tables.TryGetValue(fileNameWithoutExtension, out var value))
					{
						Tables[fileNameWithoutExtension] = dictionary;
						continue;
					}
					foreach (KeyValuePair<string, string> item in dictionary)
					{
						value[item.Key] = item.Value;
					}
				}
				catch (Exception ex)
				{
					Plugin.Log.LogWarning((object)("Failed to load lang file " + text + ": " + ex.Message));
				}
			}
		}

		private static string ReadEmbedded(string code)
		{
			string text = "CraftFromChestsPlus.Languages." + code + ".json";
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
			if (stream == null)
			{
				Plugin.Log.LogWarning((object)("Missing embedded language resource: " + text));
				return null;
			}
			using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
			return streamReader.ReadToEnd();
		}

		internal static void ApplyLanguagePreference()
		{
			string a = ModConfig.Language?.Value ?? "Auto";
			if (string.Equals(a, "Portuguese", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "pt", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "pt-BR", StringComparison.OrdinalIgnoreCase))
			{
				_activeCode = (Tables.ContainsKey("pt") ? "pt" : "en");
				return;
			}
			if (string.Equals(a, "English", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "en", StringComparison.OrdinalIgnoreCase))
			{
				_activeCode = "en";
				return;
			}
			try
			{
				string text = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : null);
				if (!string.IsNullOrEmpty(text) && (text.IndexOf("Portuguese", StringComparison.OrdinalIgnoreCase) >= 0 || text.StartsWith("pt", StringComparison.OrdinalIgnoreCase) || text.IndexOf("Brazil", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					_activeCode = (Tables.ContainsKey("pt") ? "pt" : "en");
					return;
				}
			}
			catch
			{
			}
			_activeCode = "en";
		}

		internal static Dictionary<string, string> ParseFlatJson(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(json))
			{
				return dictionary;
			}
			int i = 0;
			SkipWs(json, ref i);
			if (i >= json.Length || json[i] != '{')
			{
				return dictionary;
			}
			i++;
			while (i < json.Length)
			{
				SkipWs(json, ref i);
				if (i < json.Length && json[i] == '}')
				{
					break;
				}
				if (i < json.Length && json[i] == ',')
				{
					i++;
					continue;
				}
				if (!TryReadString(json, ref i, out var value))
				{
					break;
				}
				SkipWs(json, ref i);
				if (i >= json.Length || json[i] != ':')
				{
					break;
				}
				i++;
				SkipWs(json, ref i);
				if (!TryReadString(json, ref i, out var value2))
				{
					break;
				}
				dictionary[value] = value2;
			}
			return dictionary;
		}

		private static void SkipWs(string s, ref int i)
		{
			while (i < s.Length && char.IsWhiteSpace(s[i]))
			{
				i++;
			}
		}

		private static bool TryReadString(string s, ref int i, out string value)
		{
			value = null;
			SkipWs(s, ref i);
			if (i >= s.Length || s[i] != '"')
			{
				return false;
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					value = stringBuilder.ToString();
					return true;
				case '\\':
					if (i < s.Length)
					{
						char c2 = s[i++];
						StringBuilder stringBuilder2 = stringBuilder;
						stringBuilder2.Append(c2 switch
						{
							'n' => '\n', 
							'r' => '\r', 
							't' => '\t', 
							'"' => '"', 
							'\\' => '\\', 
							_ => c2, 
						});
						continue;
					}
					break;
				}
				stringBuilder.Append(c);
			}
			return false;
		}
	}
}
namespace CraftFromChestsPlus.Effects
{
	internal static class PullFeedback
	{
		private static float _lastVfxTime;

		private const float VfxCooldown = 0.08f;

		internal static void OnPulledFromChest(string itemSharedName, Vector3 chestPos, Vector3 targetPos)
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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)
			if (!ModConfig.VisualFeedback.Value)
			{
				return;
			}
			float time = Time.time;
			if (time - _lastVfxTime < 0.08f)
			{
				return;
			}
			_lastVfxTime = time;
			PlayPrefabSafe("vfx_Potion_health_medium", chestPos + Vector3.up * 0.4f);
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				try
				{
					EffectList autopickupEffects = localPlayer.m_autopickupEffects;
					if (autopickupEffects != null)
					{
						autopickupEffects.Create(targetPos, Quaternion.identity, (Transform)null, 1f, -1, ZDOID.None);
					}
				}
				catch
				{
				}
			}
			PlayPrefabSafe("sfx_lootspawn", targetPos);
			if (ModConfig.FlyingItemEffect.Value)
			{
				SpawnTrail(chestPos + Vector3.up * 0.6f, targetPos + Vector3.up * 1.1f);
			}
		}

		private static void PlayPrefabSafe(string prefabName, Vector3 pos)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)ZNetScene.instance == (Object)null))
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
					if (!((Object)(object)prefab == (Object)null))
					{
						Object.Instantiate<GameObject>(prefab, pos, Quaternion.identity);
					}
				}
			}
			catch
			{
			}
		}

		private static void SpawnTrail(Vector3 from, Vector3 to)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
				((Object)obj).name = "CFC_PullTrail";
				Object.Destroy((Object)(object)obj.GetComponent<Collider>());
				obj.transform.position = from;
				obj.transform.localScale = Vector3.one * 0.12f;
				Renderer component = obj.GetComponent<Renderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.material = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Standard"));
					component.material.color = new Color(0.35f, 0.85f, 1f, 0.85f);
				}
				obj.AddComponent<PullFlyer>().Begin(from, to, 0.4f);
			}
			catch
			{
			}
		}
	}
	internal sealed class PullFlyer : MonoBehaviour
	{
		private Vector3 _from;

		private Vector3 _to;

		private float _duration;

		private float _t;

		private Vector3 _arcPeak;

		internal void Begin(Vector3 from, Vector3 to, float duration)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			_from = from;
			_to = to;
			_duration = Mathf.Max(0.05f, duration);
			_t = 0f;
			_arcPeak = Vector3.Lerp(from, to, 0.5f) + Vector3.up * Mathf.Clamp(Vector3.Distance(from, to) * 0.15f, 0.4f, 2.5f);
		}

		private void Update()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0045: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			_t += Time.deltaTime / _duration;
			float num = Mathf.Clamp01(_t);
			Vector3 val = Vector3.Lerp(_from, _arcPeak, num);
			Vector3 val2 = Vector3.Lerp(_arcPeak, _to, num);
			((Component)this).transform.position = Vector3.Lerp(val, val2, num);
			if (num >= 1f)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
}
namespace CraftFromChestsPlus.Chest
{
	internal static class NearbyChestService
	{
		private readonly struct CountKey : IEquatable<CountKey>
		{
			public readonly string Name;

			public readonly int Quality;

			public readonly bool MatchWorld;

			public CountKey(string name, int quality, bool matchWorld)
			{
				Name = name;
				Quality = quality;
				MatchWorld = matchWorld;
			}

			public bool Equals(CountKey other)
			{
				if (Quality == other.Quality && MatchWorld == other.MatchWorld)
				{
					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 != null) ? Name.GetHashCode() : 0) * 397) ^ Quality) * 397) ^ (MatchWorld ? 1 : 0);
			}
		}

		private struct CountEntry
		{
			public int Total;

			public float Time;
		}

		internal const float MinRange = 5f;

		internal const float MaxRange = 200f;

		internal const int MaxNearbyChests = 32;

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

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

		private static readonly Dictionary<CountKey, CountEntry> CountCache = new Dictionary<CountKey, CountEntry>();

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

		private static float _nextNearbyRefresh;

		private static Vector3 _lastCenter;

		private static float _lastRange;

		private static bool _trackedDirty = true;

		private static bool _bootstrapped;

		private const float NearbyRefreshInterval = 2f;

		private const float MoveRefresh = 4f;

		private const float CountCacheTtl = 0.5f;

		internal static float EffectiveRange => Mathf.Clamp(ModConfig.Range.Value, 5f, 200f);

		internal static float GetPullRangeForLocalPlayer()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				return TotemZoneService.GetActivePullRange(localPlayer);
			}
			return EffectiveRange;
		}

		internal static void Register(Container container)
		{
			if (!((Object)(object)container == (Object)null) && !Tracked.Contains(container))
			{
				Tracked.Add(container);
				_trackedDirty = true;
				InvalidateCounts();
			}
		}

		internal static void Unregister(Container container)
		{
			if (!((Object)(object)container == (Object)null))
			{
				Tracked.Remove(container);
				if ((Object)(object)container != (Object)null)
				{
					LoadedOnce.Remove(((Object)container).GetInstanceID());
				}
				_trackedDirty = true;
				InvalidateCounts();
			}
		}

		internal static void Invalidate()
		{
			_nextNearbyRefresh = 0f;
			NearbyCache.Clear();
			_trackedDirty = true;
			InvalidateCounts();
		}

		internal static void InvalidateCounts()
		{
			CountCache.Clear();
		}

		internal static List<Container> GetNearby(Vector3 center)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.Enabled.Value)
			{
				return NearbyCache;
			}
			float pullRangeForLocalPlayer = GetPullRangeForLocalPlayer();
			float time = Time.time;
			bool flag = Vector3.Distance(center, _lastCenter) > 4f;
			if (_trackedDirty || time >= _nextNearbyRefresh || flag || Mathf.Abs(pullRangeForLocalPlayer - _lastRange) > 0.01f || NearbyCache.Count == 0)
			{
				RefreshNearby(center, pullRangeForLocalPlayer);
				_nextNearbyRefresh = time + 2f;
				_lastCenter = center;
				_lastRange = pullRangeForLocalPlayer;
				_trackedDirty = false;
				InvalidateCounts();
			}
			return NearbyCache;
		}

		private static void RefreshNearby(Vector3 center, float range)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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)
			NearbyCache.Clear();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			for (int num = Tracked.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)Tracked[num] == (Object)null)
				{
					Tracked.RemoveAt(num);
				}
			}
			if (Tracked.Count == 0 && !_bootstrapped)
			{
				BootstrapScan(localPlayer);
			}
			float num2 = range * range;
			List<(Container, float)> list = new List<(Container, float)>(32);
			for (int i = 0; i < Tracked.Count; i++)
			{
				Container val = Tracked[i];
				if (IsValidChest(val, localPlayer))
				{
					Vector3 val2 = ((Component)val).transform.position - center;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (!(sqrMagnitude > num2))
					{
						list.Add((val, sqrMagnitude));
					}
				}
			}
			list.Sort(((Container c, float d) a, (Container c, float d) b) => a.d.CompareTo(b.d));
			int num3 = Mathf.Min(list.Count, 32);
			for (int num4 = 0; num4 < num3; num4++)
			{
				Container item = list[num4].Item1;
				EnsureLoaded(item);
				if (item.GetInventory() != null)
				{
					NearbyCache.Add(item);
				}
			}
		}

		private static void BootstrapScan(Player player)
		{
			_bootstrapped = true;
			Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0);
			foreach (Container container in array)
			{
				if (IsValidChest(container, player))
				{
					Register(container);
				}
			}
		}

		private static void EnsureLoaded(Container container)
		{
			try
			{
				int instanceID = ((Object)container).GetInstanceID();
				if (container.GetInventory() != null)
				{
					LoadedOnce.Add(instanceID);
				}
				else if (!LoadedOnce.Contains(instanceID))
				{
					LoadedOnce.Add(instanceID);
					container.Load();
				}
			}
			catch
			{
			}
		}

		internal static bool IsValidChest(Container container, Player player)
		{
			if ((Object)(object)container == (Object)null || (Object)(object)((Component)container).transform == (Object)null)
			{
				return false;
			}
			if (((Object)container).name.StartsWith("Treasure"))
			{
				return false;
			}
			if ((Object)(object)((Component)container).GetComponentInParent<Piece>() == (Object)null)
			{
				return false;
			}
			if ((Object)(object)container.m_nview == (Object)null || !container.m_nview.IsValid())
			{
				return false;
			}
			try
			{
				if (container.m_nview.GetZDO().GetLong(ZDOVars.s_creator, 0L) == 0L)
				{
					return false;
				}
			}
			catch
			{
				return false;
			}
			try
			{
				if ((Object)(object)player != (Object)null && !container.CheckAccess(player.GetPlayerID()))
				{
					return false;
				}
			}
			catch
			{
				return false;
			}
			return true;
		}

		internal static int CountInChests(string itemName, int quality, bool matchWorldLevel, Vector3 center)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(itemName))
			{
				return 0;
			}
			CountKey key = new CountKey(itemName, quality, matchWorldLevel);
			float time = Time.time;
			if (CountCache.TryGetValue(key, out var value) && time - value.Time <= 0.5f)
			{
				return value.Total;
			}
			int num = 0;
			List<Container> nearby = GetNearby(center);
			for (int i = 0; i < nearby.Count; i++)
			{
				Container val = nearby[i];
				if (!((Object)(object)val == (Object)null))
				{
					Inventory inventory = val.GetInventory();
					if (inventory != null)
					{
						num += inventory.CountItems(itemName, quality, matchWorldLevel);
					}
				}
			}
			CountCache[key] = new CountEntry
			{
				Total = num,
				Time = time
			};
			return num;
		}

		internal static int CountInChests(string itemName, Vector3 center)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			return CountInChests(itemName, -1, matchWorldLevel: true, center);
		}

		internal static bool TryFindOreInChests(Smelter smelter, Vector3 center, out string prefabName, out string sharedName)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			prefabName = null;
			sharedName = null;
			if (smelter?.m_conversion == null)
			{
				return false;
			}
			GetNearby(center);
			for (int i = 0; i < smelter.m_conversion.Count; i++)
			{
				ItemConversion val = smelter.m_conversion[i];
				if ((Object)(object)val?.m_from == (Object)null)
				{
					continue;
				}
				SharedData val2 = val.m_from.m_itemData?.m_shared;
				if (val2 != null)
				{
					string name = val2.m_name;
					if (CountInChests(name, -1, matchWorldLevel: true, center) > 0)
					{
						prefabName = ((Object)val.m_from).name;
						sharedName = name;
						return true;
					}
				}
			}
			return false;
		}

		internal static int RemoveFromChests(string itemName, int amount, Vector3 center)
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (amount <= 0 || string.IsNullOrEmpty(itemName))
			{
				return 0;
			}
			int num = 0;
			List<Container> nearby = GetNearby(center);
			for (int i = 0; i < nearby.Count; i++)
			{
				if (num >= amount)
				{
					break;
				}
				Container val = nearby[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Inventory inventory = val.GetInventory();
				if (inventory == null)
				{
					continue;
				}
				int num2 = inventory.CountItems(itemName, -1, true);
				if (num2 > 0)
				{
					int num3 = Mathf.Min(num2, amount - num);
					inventory.RemoveItem(itemName, num3, -1, true);
					num += num3;
					try
					{
						val.Save();
					}
					catch
					{
					}
					PullFeedback.OnPulledFromChest(itemName, ((Component)val).transform.position, center);
				}
			}
			InvalidateCounts();
			return num;
		}
	}
	[HarmonyPatch]
	internal static class ChestLifecyclePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "Awake")]
		private static void ContainerAwakePostfix(Container __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && NearbyChestService.IsValidChest(__instance, localPlayer))
			{
				NearbyChestService.Register(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Container), "OnDestroyed")]
		private static void ContainerDestroyedPostfix(Container __instance)
		{
			NearbyChestService.Unregister(__instance);
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}